Commit e3d2f927 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6:
  parisc: convert to generic compat_sys_ptrace
  parisc: add rtc platform driver
  parisc: initialize unwinder much earlier
  parisc: add new syscalls
  parisc: hijack jump to start_kernel
  parisc: add pdc_coproc_cfg_unlocked and set_firmware_width_unlocked
  parisc: move include/asm-parisc to arch/parisc/include/asm
  parisc: move pdc_result to real2.S
  parisc: unify CCIO_COLLECT_STATS implementation
  parisc: add arch/parisc/kernel/.gitignore
  parisc: ropes.h - fix <asm-parisc/*> -> <asm/*>
  parisc: parisc-agp - fix <asm-parisc/*> -> <asm/*>

Resolve remove/rename conflict: include/asm-parisc/a.out.h is no longer
relevant.
parents a9b6148d 81e192d6
...@@ -9,6 +9,8 @@ config PARISC ...@@ -9,6 +9,8 @@ config PARISC
def_bool y def_bool y
select HAVE_IDE select HAVE_IDE
select HAVE_OPROFILE select HAVE_OPROFILE
select RTC_CLASS
select RTC_DRV_PARISC
help help
The PA-RISC microprocessor is designed by Hewlett-Packard and used The PA-RISC microprocessor is designed by Hewlett-Packard and used
in many of their workstations & servers (HP9000 700 and 800 series, in many of their workstations & servers (HP9000 700 and 800 series,
......
...@@ -332,6 +332,9 @@ ...@@ -332,6 +332,9 @@
#define BOOT_CONSOLE_SPA_OFFSET 0x3c4 #define BOOT_CONSOLE_SPA_OFFSET 0x3c4
#define BOOT_CONSOLE_PATH_OFFSET 0x3a8 #define BOOT_CONSOLE_PATH_OFFSET 0x3a8
/* size of the pdc_result buffer for firmware.c */
#define NUM_PDC_RESULT 32
#if !defined(__ASSEMBLY__) #if !defined(__ASSEMBLY__)
#ifdef __KERNEL__ #ifdef __KERNEL__
...@@ -600,6 +603,7 @@ int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsi ...@@ -600,6 +603,7 @@ int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsi
int pdc_chassis_disp(unsigned long disp); int pdc_chassis_disp(unsigned long disp);
int pdc_chassis_warn(unsigned long *warn); int pdc_chassis_warn(unsigned long *warn);
int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info); int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info);
int pdc_coproc_cfg_unlocked(struct pdc_coproc_cfg *pdc_coproc_info);
int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index, int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
void *iodc_data, unsigned int iodc_data_size); void *iodc_data, unsigned int iodc_data_size);
int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info, int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info,
...@@ -638,6 +642,7 @@ int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr, ...@@ -638,6 +642,7 @@ int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
#endif #endif
void set_firmware_width(void); void set_firmware_width(void);
void set_firmware_width_unlocked(void);
int pdc_do_firm_test_reset(unsigned long ftc_bitmap); int pdc_do_firm_test_reset(unsigned long ftc_bitmap);
int pdc_do_reset(void); int pdc_do_reset(void);
int pdc_soft_power_info(unsigned long *power_reg); int pdc_soft_power_info(unsigned long *power_reg);
......
...@@ -47,6 +47,16 @@ struct pt_regs { ...@@ -47,6 +47,16 @@ struct pt_regs {
#define task_regs(task) ((struct pt_regs *) ((char *)(task) + TASK_REGS)) #define task_regs(task) ((struct pt_regs *) ((char *)(task) + TASK_REGS))
#define __ARCH_WANT_COMPAT_SYS_PTRACE
struct task_struct;
#define arch_has_single_step() 1
void user_disable_single_step(struct task_struct *task);
void user_enable_single_step(struct task_struct *task);
#define arch_has_block_step() 1
void user_enable_block_step(struct task_struct *task);
/* XXX should we use iaoq[1] or iaoq[0] ? */ /* XXX should we use iaoq[1] or iaoq[0] ? */
#define user_mode(regs) (((regs)->iaoq[0] & 3) ? 1 : 0) #define user_mode(regs) (((regs)->iaoq[0] & 3) ? 1 : 0)
#define user_space(regs) (((regs)->iasq[1] != 0) ? 1 : 0) #define user_space(regs) (((regs)->iasq[1] != 0) ? 1 : 0)
......
#ifndef _ASM_PARISC_ROPES_H_ #ifndef _ASM_PARISC_ROPES_H_
#define _ASM_PARISC_ROPES_H_ #define _ASM_PARISC_ROPES_H_
#include <asm-parisc/parisc-device.h> #include <asm/parisc-device.h>
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */ /* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */
......
...@@ -801,8 +801,14 @@ ...@@ -801,8 +801,14 @@
#define __NR_timerfd_create (__NR_Linux + 306) #define __NR_timerfd_create (__NR_Linux + 306)
#define __NR_timerfd_settime (__NR_Linux + 307) #define __NR_timerfd_settime (__NR_Linux + 307)
#define __NR_timerfd_gettime (__NR_Linux + 308) #define __NR_timerfd_gettime (__NR_Linux + 308)
#define __NR_signalfd4 (__NR_Linux + 309)
#define __NR_Linux_syscalls (__NR_timerfd_gettime + 1) #define __NR_eventfd2 (__NR_Linux + 310)
#define __NR_epoll_create1 (__NR_Linux + 311)
#define __NR_dup3 (__NR_Linux + 312)
#define __NR_pipe2 (__NR_Linux + 313)
#define __NR_inotify_init1 (__NR_Linux + 314)
#define __NR_Linux_syscalls (__NR_inotify_init1 + 1)
#define __IGNORE_select /* newselect */ #define __IGNORE_select /* newselect */
......
...@@ -74,4 +74,6 @@ void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *r ...@@ -74,4 +74,6 @@ void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *r
int unwind_once(struct unwind_frame_info *info); int unwind_once(struct unwind_frame_info *info);
int unwind_to_user(struct unwind_frame_info *info); int unwind_to_user(struct unwind_frame_info *info);
int unwind_init(void);
#endif #endif
...@@ -290,5 +290,8 @@ int main(void) ...@@ -290,5 +290,8 @@ int main(void)
DEFINE(EXCDATA_IP, offsetof(struct exception_data, fault_ip)); DEFINE(EXCDATA_IP, offsetof(struct exception_data, fault_ip));
DEFINE(EXCDATA_SPACE, offsetof(struct exception_data, fault_space)); DEFINE(EXCDATA_SPACE, offsetof(struct exception_data, fault_space));
DEFINE(EXCDATA_ADDR, offsetof(struct exception_data, fault_addr)); DEFINE(EXCDATA_ADDR, offsetof(struct exception_data, fault_addr));
BLANK();
DEFINE(ASM_PDC_RESULT_SIZE, NUM_PDC_RESULT * sizeof(unsigned long));
BLANK();
return 0; return 0;
} }
...@@ -71,8 +71,8 @@ ...@@ -71,8 +71,8 @@
#include <asm/processor.h> /* for boot_cpu_data */ #include <asm/processor.h> /* for boot_cpu_data */
static DEFINE_SPINLOCK(pdc_lock); static DEFINE_SPINLOCK(pdc_lock);
static unsigned long pdc_result[32] __attribute__ ((aligned (8))); extern unsigned long pdc_result[NUM_PDC_RESULT];
static unsigned long pdc_result2[32] __attribute__ ((aligned (8))); extern unsigned long pdc_result2[NUM_PDC_RESULT];
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
#define WIDE_FIRMWARE 0x1 #define WIDE_FIRMWARE 0x1
...@@ -150,26 +150,40 @@ static void convert_to_wide(unsigned long *addr) ...@@ -150,26 +150,40 @@ static void convert_to_wide(unsigned long *addr)
#endif #endif
} }
#ifdef CONFIG_64BIT
void __init set_firmware_width_unlocked(void)
{
int ret;
ret = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES,
__pa(pdc_result), 0);
convert_to_wide(pdc_result);
if (pdc_result[0] != NARROW_FIRMWARE)
parisc_narrow_firmware = 0;
}
/** /**
* set_firmware_width - Determine if the firmware is wide or narrow. * set_firmware_width - Determine if the firmware is wide or narrow.
* *
* This function must be called before any pdc_* function that uses the convert_to_wide * This function must be called before any pdc_* function that uses the
* function. * convert_to_wide function.
*/ */
void __init set_firmware_width(void) void __init set_firmware_width(void)
{ {
#ifdef CONFIG_64BIT
int retval;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&pdc_lock, flags); spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0); set_firmware_width_unlocked();
convert_to_wide(pdc_result);
if(pdc_result[0] != NARROW_FIRMWARE)
parisc_narrow_firmware = 0;
spin_unlock_irqrestore(&pdc_lock, flags); spin_unlock_irqrestore(&pdc_lock, flags);
#endif
} }
#else
void __init set_firmware_width_unlocked(void) {
return;
}
void __init set_firmware_width(void) {
return;
}
#endif /*CONFIG_64BIT*/
/** /**
* pdc_emergency_unlock - Unlock the linux pdc lock * pdc_emergency_unlock - Unlock the linux pdc lock
...@@ -288,6 +302,20 @@ int pdc_chassis_warn(unsigned long *warn) ...@@ -288,6 +302,20 @@ int pdc_chassis_warn(unsigned long *warn)
return retval; return retval;
} }
int __init pdc_coproc_cfg_unlocked(struct pdc_coproc_cfg *pdc_coproc_info)
{
int ret;
ret = mem_pdc_call(PDC_COPROC, PDC_COPROC_CFG, __pa(pdc_result));
convert_to_wide(pdc_result);
pdc_coproc_info->ccr_functional = pdc_result[0];
pdc_coproc_info->ccr_present = pdc_result[1];
pdc_coproc_info->revision = pdc_result[17];
pdc_coproc_info->model = pdc_result[18];
return ret;
}
/** /**
* pdc_coproc_cfg - To identify coprocessors attached to the processor. * pdc_coproc_cfg - To identify coprocessors attached to the processor.
* @pdc_coproc_info: Return buffer address. * @pdc_coproc_info: Return buffer address.
...@@ -297,19 +325,14 @@ int pdc_chassis_warn(unsigned long *warn) ...@@ -297,19 +325,14 @@ int pdc_chassis_warn(unsigned long *warn)
*/ */
int __init pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info) int __init pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info)
{ {
int retval; int ret;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&pdc_lock, flags); spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_COPROC, PDC_COPROC_CFG, __pa(pdc_result)); ret = pdc_coproc_cfg_unlocked(pdc_coproc_info);
convert_to_wide(pdc_result);
pdc_coproc_info->ccr_functional = pdc_result[0];
pdc_coproc_info->ccr_present = pdc_result[1];
pdc_coproc_info->revision = pdc_result[17];
pdc_coproc_info->model = pdc_result[18];
spin_unlock_irqrestore(&pdc_lock, flags); spin_unlock_irqrestore(&pdc_lock, flags);
return retval; return ret;
} }
/** /**
......
...@@ -121,7 +121,7 @@ $pgt_fill_loop: ...@@ -121,7 +121,7 @@ $pgt_fill_loop:
copy %r0,%r2 copy %r0,%r2
/* And the RFI Target address too */ /* And the RFI Target address too */
load32 start_kernel,%r11 load32 start_parisc,%r11
/* And the initial task pointer */ /* And the initial task pointer */
load32 init_thread_union,%r6 load32 init_thread_union,%r6
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright (C) 2000 Hewlett-Packard Co, Linuxcare Inc. * Copyright (C) 2000 Hewlett-Packard Co, Linuxcare Inc.
* Copyright (C) 2000 Matthew Wilcox <matthew@wil.cx> * Copyright (C) 2000 Matthew Wilcox <matthew@wil.cx>
* Copyright (C) 2000 David Huggins-Daines <dhd@debian.org> * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org>
* Copyright (C) 2008 Helge Deller <deller@gmx.de>
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -27,15 +28,149 @@ ...@@ -27,15 +28,149 @@
/* PSW bits we allow the debugger to modify */ /* PSW bits we allow the debugger to modify */
#define USER_PSW_BITS (PSW_N | PSW_V | PSW_CB) #define USER_PSW_BITS (PSW_N | PSW_V | PSW_CB)
#undef DEBUG_PTRACE /*
* Called by kernel/ptrace.c when detaching..
*
* Make sure single step bits etc are not set.
*/
void ptrace_disable(struct task_struct *task)
{
task->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
/* make sure the trap bits are not set */
pa_psw(task)->r = 0;
pa_psw(task)->t = 0;
pa_psw(task)->h = 0;
pa_psw(task)->l = 0;
}
/*
* The following functions are called by ptrace_resume() when
* enabling or disabling single/block tracing.
*/
void user_disable_single_step(struct task_struct *task)
{
ptrace_disable(task);
}
void user_enable_single_step(struct task_struct *task)
{
task->ptrace &= ~PT_BLOCKSTEP;
task->ptrace |= PT_SINGLESTEP;
if (pa_psw(task)->n) {
struct siginfo si;
/* Nullified, just crank over the queue. */
task_regs(task)->iaoq[0] = task_regs(task)->iaoq[1];
task_regs(task)->iasq[0] = task_regs(task)->iasq[1];
task_regs(task)->iaoq[1] = task_regs(task)->iaoq[0] + 4;
pa_psw(task)->n = 0;
pa_psw(task)->x = 0;
pa_psw(task)->y = 0;
pa_psw(task)->z = 0;
pa_psw(task)->b = 0;
ptrace_disable(task);
/* Don't wake up the task, but let the
parent know something happened. */
si.si_code = TRAP_TRACE;
si.si_addr = (void __user *) (task_regs(task)->iaoq[0] & ~3);
si.si_signo = SIGTRAP;
si.si_errno = 0;
force_sig_info(SIGTRAP, &si, task);
/* notify_parent(task, SIGCHLD); */
return;
}
/* Enable recovery counter traps. The recovery counter
* itself will be set to zero on a task switch. If the
* task is suspended on a syscall then the syscall return
* path will overwrite the recovery counter with a suitable
* value such that it traps once back in user space. We
* disable interrupts in the tasks PSW here also, to avoid
* interrupts while the recovery counter is decrementing.
*/
pa_psw(task)->r = 1;
pa_psw(task)->t = 0;
pa_psw(task)->h = 0;
pa_psw(task)->l = 0;
}
void user_enable_block_step(struct task_struct *task)
{
task->ptrace &= ~PT_SINGLESTEP;
task->ptrace |= PT_BLOCKSTEP;
/* Enable taken branch trap. */
pa_psw(task)->r = 0;
pa_psw(task)->t = 1;
pa_psw(task)->h = 0;
pa_psw(task)->l = 0;
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
unsigned long tmp;
long ret = -EIO;
switch (request) {
/* 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))
break;
tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
ret = put_user(tmp, (unsigned long *) data);
break;
/* Write the word at location addr in the USER area. This will need
to change when the kernel no longer saves all regs on a syscall.
FIXME. There is a problem at the moment in that r3-r18 are only
saved if the process is ptraced on syscall entry, and even then
those values are overwritten by actual register values on syscall
exit. */
case PTRACE_POKEUSR:
/* Some register values written here may be ignored in
* entry.S:syscall_restore_rfi; e.g. iaoq is written with
* r31/r31+4, and not with the values in pt_regs.
*/
if (addr == PT_PSW) {
/* Allow writing to Nullify, Divide-step-correction,
* and carry/borrow bits.
* BEWARE, if you set N, and then single step, it won't
* stop on the nullified instruction.
*/
data &= USER_PSW_BITS;
task_regs(child)->gr[0] &= ~USER_PSW_BITS;
task_regs(child)->gr[0] |= data;
ret = 0;
break;
}
if ((addr & (sizeof(long)-1)) ||
(unsigned long) addr >= sizeof(struct pt_regs))
break;
if ((addr >= PT_GR1 && addr <= PT_GR31) ||
addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
(addr >= PT_FR0 && addr <= PT_FR31 + 4) ||
addr == PT_SAR) {
*(unsigned long *) ((char *) task_regs(child) + addr) = data;
ret = 0;
}
break;
default:
ret = ptrace_request(child, request, addr, data);
break;
}
return ret;
}
#ifdef DEBUG_PTRACE
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
#ifdef CONFIG_64BIT #ifdef CONFIG_COMPAT
/* This function is needed to translate 32 bit pt_regs offsets in to /* This function is needed to translate 32 bit pt_regs offsets in to
* 64 bit pt_regs offsets. For example, a 32 bit gdb under a 64 bit kernel * 64 bit pt_regs offsets. For example, a 32 bit gdb under a 64 bit kernel
...@@ -61,106 +196,25 @@ static long translate_usr_offset(long offset) ...@@ -61,106 +196,25 @@ static long translate_usr_offset(long offset)
else else
return -1; return -1;
} }
#endif
/*
* Called by kernel/ptrace.c when detaching..
*
* Make sure single step bits etc are not set.
*/
void ptrace_disable(struct task_struct *child)
{
/* make sure the trap bits are not set */
pa_psw(child)->r = 0;
pa_psw(child)->t = 0;
pa_psw(child)->h = 0;
pa_psw(child)->l = 0;
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data) long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
compat_ulong_t addr, compat_ulong_t data)
{ {
long ret; compat_uint_t tmp;
#ifdef DEBUG_PTRACE long ret = -EIO;
long oaddr=addr, odata=data;
#endif
switch (request) { switch (request) {
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA: {
#ifdef CONFIG_64BIT
if (__is_compat_task(child)) {
int copied;
unsigned int tmp;
addr &= 0xffffffffL;
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
ret = -EIO;
if (copied != sizeof(tmp))
goto out_tsk;
ret = put_user(tmp,(unsigned int *) data);
DBG("sys_ptrace(PEEK%s, %d, %lx, %lx) returning %ld, data %x\n",
request == PTRACE_PEEKTEXT ? "TEXT" : "DATA",
pid, oaddr, odata, ret, tmp);
}
else
#endif
ret = generic_ptrace_peekdata(child, addr, data);
goto out_tsk;
}
/* when I and D space are separate, this will have to be fixed. */ case PTRACE_PEEKUSR:
case PTRACE_POKETEXT: /* write the word at location addr. */ if (addr & (sizeof(compat_uint_t)-1))
case PTRACE_POKEDATA: break;
ret = 0; addr = translate_usr_offset(addr);
#ifdef CONFIG_64BIT if (addr < 0)
if (__is_compat_task(child)) { break;
unsigned int tmp = (unsigned int)data;
DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
request == PTRACE_POKETEXT ? "TEXT" : "DATA",
pid, oaddr, odata);
addr &= 0xffffffffL;
if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) == sizeof(tmp))
goto out_tsk;
}
else
#endif
{
if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
goto out_tsk;
}
ret = -EIO;
goto out_tsk;
/* Read the word at location addr in the USER area. For ptraced tmp = *(compat_uint_t *) ((char *) task_regs(child) + addr);
processes, the kernel saves all regs on a syscall. */ ret = put_user(tmp, (compat_uint_t *) (unsigned long) data);
case PTRACE_PEEKUSR: { break;
ret = -EIO;
#ifdef CONFIG_64BIT
if (__is_compat_task(child)) {
unsigned int tmp;
if (addr & (sizeof(int)-1))
goto out_tsk;
if ((addr = translate_usr_offset(addr)) < 0)
goto out_tsk;
tmp = *(unsigned int *) ((char *) task_regs(child) + addr);
ret = put_user(tmp, (unsigned int *) data);
DBG("sys_ptrace(PEEKUSR, %d, %lx, %lx) returning %ld, addr %lx, data %x\n",
pid, oaddr, odata, ret, addr, tmp);
}
else
#endif
{
unsigned long tmp;
if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
goto out_tsk;
tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
ret = put_user(tmp, (unsigned long *) data);
}
goto out_tsk;
}
/* Write the word at location addr in the USER area. This will need /* Write the word at location addr in the USER area. This will need
to change when the kernel no longer saves all regs on a syscall. to change when the kernel no longer saves all regs on a syscall.
...@@ -169,185 +223,46 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ...@@ -169,185 +223,46 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
those values are overwritten by actual register values on syscall those values are overwritten by actual register values on syscall
exit. */ exit. */
case PTRACE_POKEUSR: case PTRACE_POKEUSR:
ret = -EIO;
/* Some register values written here may be ignored in /* Some register values written here may be ignored in
* entry.S:syscall_restore_rfi; e.g. iaoq is written with * entry.S:syscall_restore_rfi; e.g. iaoq is written with
* r31/r31+4, and not with the values in pt_regs. * r31/r31+4, and not with the values in pt_regs.
*/ */
/* PT_PSW=0, so this is valid for 32 bit processes under 64
* bit kernels.
*/
if (addr == PT_PSW) { if (addr == PT_PSW) {
/* PT_PSW=0, so this is valid for 32 bit processes /* Since PT_PSW==0, it is valid for 32 bit processes
* under 64 bit kernels. * under 64 bit kernels as well.
*
* Allow writing to Nullify, Divide-step-correction,
* and carry/borrow bits.
* BEWARE, if you set N, and then single step, it won't
* stop on the nullified instruction.
*/ */
DBG("sys_ptrace(POKEUSR, %d, %lx, %lx)\n", ret = arch_ptrace(child, request, addr, data);
pid, oaddr, odata); } else {
data &= USER_PSW_BITS; if (addr & (sizeof(compat_uint_t)-1))
task_regs(child)->gr[0] &= ~USER_PSW_BITS; break;
task_regs(child)->gr[0] |= data; addr = translate_usr_offset(addr);
ret = 0; if (addr < 0)
goto out_tsk; break;
}
#ifdef CONFIG_64BIT
if (__is_compat_task(child)) {
if (addr & (sizeof(int)-1))
goto out_tsk;
if ((addr = translate_usr_offset(addr)) < 0)
goto out_tsk;
DBG("sys_ptrace(POKEUSR, %d, %lx, %lx) addr %lx\n",
pid, oaddr, odata, addr);
if (addr >= PT_FR0 && addr <= PT_FR31 + 4) { if (addr >= PT_FR0 && addr <= PT_FR31 + 4) {
/* Special case, fp regs are 64 bits anyway */ /* Special case, fp regs are 64 bits anyway */
*(unsigned int *) ((char *) task_regs(child) + addr) = data; *(__u64 *) ((char *) task_regs(child) + addr) = data;
ret = 0; ret = 0;
} }
else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) || else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 || addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 ||
addr == PT_SAR+4) { addr == PT_SAR+4) {
/* Zero the top 32 bits */ /* Zero the top 32 bits */
*(unsigned int *) ((char *) task_regs(child) + addr - 4) = 0; *(__u32 *) ((char *) task_regs(child) + addr - 4) = 0;
*(unsigned int *) ((char *) task_regs(child) + addr) = data; *(__u32 *) ((char *) task_regs(child) + addr) = data;
ret = 0;
}
goto out_tsk;
}
else
#endif
{
if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
goto out_tsk;
if ((addr >= PT_GR1 && addr <= PT_GR31) ||
addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
(addr >= PT_FR0 && addr <= PT_FR31 + 4) ||
addr == PT_SAR) {
*(unsigned long *) ((char *) task_regs(child) + addr) = data;
ret = 0; ret = 0;
} }
goto out_tsk;
}
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT:
ret = -EIO;
DBG("sys_ptrace(%s)\n",
request == PTRACE_SYSCALL ? "SYSCALL" : "CONT");
if (!valid_signal(data))
goto out_tsk;
child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
if (request == PTRACE_SYSCALL) {
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
} else {
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
} }
child->exit_code = data; break;
goto out_wake_notrap;
case PTRACE_KILL:
/*
* make the child exit. Best I can do is send it a
* sigkill. perhaps it should be put in the status
* that it wants to exit.
*/
ret = 0;
DBG("sys_ptrace(KILL)\n");
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
goto out_tsk;
child->exit_code = SIGKILL;
goto out_wake_notrap;
case PTRACE_SINGLEBLOCK:
DBG("sys_ptrace(SINGLEBLOCK)\n");
ret = -EIO;
if (!valid_signal(data))
goto out_tsk;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->ptrace &= ~PT_SINGLESTEP;
child->ptrace |= PT_BLOCKSTEP;
child->exit_code = data;
/* Enable taken branch trap. */
pa_psw(child)->r = 0;
pa_psw(child)->t = 1;
pa_psw(child)->h = 0;
pa_psw(child)->l = 0;
goto out_wake;
case PTRACE_SINGLESTEP:
DBG("sys_ptrace(SINGLESTEP)\n");
ret = -EIO;
if (!valid_signal(data))
goto out_tsk;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->ptrace &= ~PT_BLOCKSTEP;
child->ptrace |= PT_SINGLESTEP;
child->exit_code = data;
if (pa_psw(child)->n) {
struct siginfo si;
/* Nullified, just crank over the queue. */
task_regs(child)->iaoq[0] = task_regs(child)->iaoq[1];
task_regs(child)->iasq[0] = task_regs(child)->iasq[1];
task_regs(child)->iaoq[1] = task_regs(child)->iaoq[0] + 4;
pa_psw(child)->n = 0;
pa_psw(child)->x = 0;
pa_psw(child)->y = 0;
pa_psw(child)->z = 0;
pa_psw(child)->b = 0;
ptrace_disable(child);
/* Don't wake up the child, but let the
parent know something happened. */
si.si_code = TRAP_TRACE;
si.si_addr = (void __user *) (task_regs(child)->iaoq[0] & ~3);
si.si_signo = SIGTRAP;
si.si_errno = 0;
force_sig_info(SIGTRAP, &si, child);
//notify_parent(child, SIGCHLD);
//ret = 0;
goto out_wake;
}
/* Enable recovery counter traps. The recovery counter
* itself will be set to zero on a task switch. If the
* task is suspended on a syscall then the syscall return
* path will overwrite the recovery counter with a suitable
* value such that it traps once back in user space. We
* disable interrupts in the childs PSW here also, to avoid
* interrupts while the recovery counter is decrementing.
*/
pa_psw(child)->r = 1;
pa_psw(child)->t = 0;
pa_psw(child)->h = 0;
pa_psw(child)->l = 0;
/* give it a chance to run. */
goto out_wake;
case PTRACE_GETEVENTMSG:
ret = put_user(child->ptrace_message, (unsigned int __user *) data);
goto out_tsk;
default: default:
ret = ptrace_request(child, request, addr, data); ret = compat_ptrace_request(child, request, addr, data);
goto out_tsk; break;
} }
out_wake_notrap:
ptrace_disable(child);
out_wake:
wake_up_process(child);
ret = 0;
out_tsk:
DBG("arch_ptrace(%ld, %d, %lx, %lx) returning %ld\n",
request, pid, oaddr, odata, ret);
return ret; return ret;
} }
#endif
void syscall_trace(void) void syscall_trace(void)
{ {
......
...@@ -8,12 +8,24 @@ ...@@ -8,12 +8,24 @@
* *
*/ */
#include <asm/pdc.h>
#include <asm/psw.h> #include <asm/psw.h>
#include <asm/assembly.h> #include <asm/assembly.h>
#include <asm/asm-offsets.h>
#include <linux/linkage.h> #include <linux/linkage.h>
.section .bss .section .bss
.export pdc_result
.export pdc_result2
.align 8
pdc_result:
.block ASM_PDC_RESULT_SIZE
pdc_result2:
.block ASM_PDC_RESULT_SIZE
.export real_stack .export real_stack
.export real32_stack .export real32_stack
.export real64_stack .export real64_stack
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <asm/pdc_chassis.h> #include <asm/pdc_chassis.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/unwind.h>
static char __initdata command_line[COMMAND_LINE_SIZE]; static char __initdata command_line[COMMAND_LINE_SIZE];
...@@ -123,6 +124,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -123,6 +124,7 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
extern int parisc_narrow_firmware; extern int parisc_narrow_firmware;
#endif #endif
unwind_init();
init_per_cpu(smp_processor_id()); /* Set Modes & Enable FP */ init_per_cpu(smp_processor_id()); /* Set Modes & Enable FP */
...@@ -368,6 +370,31 @@ static int __init parisc_init(void) ...@@ -368,6 +370,31 @@ static int __init parisc_init(void)
return 0; return 0;
} }
arch_initcall(parisc_init); arch_initcall(parisc_init);
void start_parisc(void)
{
extern void start_kernel(void);
int ret, cpunum;
struct pdc_coproc_cfg coproc_cfg;
cpunum = smp_processor_id();
set_firmware_width_unlocked();
ret = pdc_coproc_cfg_unlocked(&coproc_cfg);
if (ret >= 0 && coproc_cfg.ccr_functional) {
mtctl(coproc_cfg.ccr_functional, 10);
cpu_data[cpunum].fp_rev = coproc_cfg.revision;
cpu_data[cpunum].fp_model = coproc_cfg.model;
asm volatile ("fstd %fr0,8(%sp)");
} else {
panic("must have an fpu to boot linux");
}
start_kernel();
// not reached
}
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
ENTRY_SAME(setuid) ENTRY_SAME(setuid)
ENTRY_SAME(getuid) ENTRY_SAME(getuid)
ENTRY_COMP(stime) /* 25 */ ENTRY_COMP(stime) /* 25 */
ENTRY_SAME(ptrace) ENTRY_COMP(ptrace)
ENTRY_SAME(alarm) ENTRY_SAME(alarm)
/* see stat comment */ /* see stat comment */
ENTRY_COMP(newfstat) ENTRY_COMP(newfstat)
...@@ -407,6 +407,12 @@ ...@@ -407,6 +407,12 @@
ENTRY_SAME(timerfd_create) ENTRY_SAME(timerfd_create)
ENTRY_COMP(timerfd_settime) ENTRY_COMP(timerfd_settime)
ENTRY_COMP(timerfd_gettime) ENTRY_COMP(timerfd_gettime)
ENTRY_COMP(signalfd4)
ENTRY_SAME(eventfd2) /* 310 */
ENTRY_SAME(epoll_create1)
ENTRY_SAME(dup3)
ENTRY_SAME(pipe2)
ENTRY_SAME(inotify_init1)
/* Nothing yet */ /* Nothing yet */
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/profile.h> #include <linux/profile.h>
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -215,6 +216,24 @@ void __init start_cpu_itimer(void) ...@@ -215,6 +216,24 @@ void __init start_cpu_itimer(void)
cpu_data[cpu].it_value = next_tick; cpu_data[cpu].it_value = next_tick;
} }
struct platform_device rtc_parisc_dev = {
.name = "rtc-parisc",
.id = -1,
};
static int __init rtc_init(void)
{
int ret;
ret = platform_device_register(&rtc_parisc_dev);
if (ret < 0)
printk(KERN_ERR "unable to register rtc device...\n");
/* not necessarily an error */
return 0;
}
module_init(rtc_init);
void __init time_init(void) void __init time_init(void)
{ {
static struct pdc_tod tod_data; static struct pdc_tod tod_data;
...@@ -245,4 +264,3 @@ void __init time_init(void) ...@@ -245,4 +264,3 @@ void __init time_init(void)
xtime.tv_nsec = 0; xtime.tv_nsec = 0;
} }
} }
...@@ -170,7 +170,7 @@ void unwind_table_remove(struct unwind_table *table) ...@@ -170,7 +170,7 @@ void unwind_table_remove(struct unwind_table *table)
} }
/* Called from setup_arch to import the kernel unwind info */ /* Called from setup_arch to import the kernel unwind info */
static int unwind_init(void) int unwind_init(void)
{ {
long start, stop; long start, stop;
register unsigned long gp __asm__ ("r27"); register unsigned long gp __asm__ ("r27");
...@@ -417,5 +417,3 @@ int unwind_to_user(struct unwind_frame_info *info) ...@@ -417,5 +417,3 @@ int unwind_to_user(struct unwind_frame_info *info)
return ret; return ret;
} }
module_init(unwind_init);
...@@ -20,8 +20,8 @@ ...@@ -20,8 +20,8 @@
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <asm-parisc/parisc-device.h> #include <asm/parisc-device.h>
#include <asm-parisc/ropes.h> #include <asm/ropes.h>
#include "agp.h" #include "agp.h"
......
...@@ -66,15 +66,8 @@ ...@@ -66,15 +66,8 @@
#undef DEBUG_CCIO_RUN_SG #undef DEBUG_CCIO_RUN_SG
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
/* /* depends on proc fs support. But costs CPU performance. */
* CCIO_SEARCH_TIME can help measure how fast the bitmap search is. #undef CCIO_COLLECT_STATS
* impacts performance though - ditch it if you don't use it.
*/
#define CCIO_SEARCH_TIME
#undef CCIO_MAP_STATS
#else
#undef CCIO_SEARCH_TIME
#undef CCIO_MAP_STATS
#endif #endif
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
...@@ -239,12 +232,10 @@ struct ioc { ...@@ -239,12 +232,10 @@ struct ioc {
u32 res_size; /* size of resource map in bytes */ u32 res_size; /* size of resource map in bytes */
spinlock_t res_lock; spinlock_t res_lock;
#ifdef CCIO_SEARCH_TIME #ifdef CCIO_COLLECT_STATS
#define CCIO_SEARCH_SAMPLE 0x100 #define CCIO_SEARCH_SAMPLE 0x100
unsigned long avg_search[CCIO_SEARCH_SAMPLE]; unsigned long avg_search[CCIO_SEARCH_SAMPLE];
unsigned long avg_idx; /* current index into avg_search */ unsigned long avg_idx; /* current index into avg_search */
#endif
#ifdef CCIO_MAP_STATS
unsigned long used_pages; unsigned long used_pages;
unsigned long msingle_calls; unsigned long msingle_calls;
unsigned long msingle_pages; unsigned long msingle_pages;
...@@ -351,7 +342,7 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size) ...@@ -351,7 +342,7 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size)
unsigned int pages_needed = size >> IOVP_SHIFT; unsigned int pages_needed = size >> IOVP_SHIFT;
unsigned int res_idx; unsigned int res_idx;
unsigned long boundary_size; unsigned long boundary_size;
#ifdef CCIO_SEARCH_TIME #ifdef CCIO_COLLECT_STATS
unsigned long cr_start = mfctl(16); unsigned long cr_start = mfctl(16);
#endif #endif
...@@ -406,7 +397,7 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size) ...@@ -406,7 +397,7 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size)
DBG_RES("%s() res_idx %d res_hint: %d\n", DBG_RES("%s() res_idx %d res_hint: %d\n",
__func__, res_idx, ioc->res_hint); __func__, res_idx, ioc->res_hint);
#ifdef CCIO_SEARCH_TIME #ifdef CCIO_COLLECT_STATS
{ {
unsigned long cr_end = mfctl(16); unsigned long cr_end = mfctl(16);
unsigned long tmp = cr_end - cr_start; unsigned long tmp = cr_end - cr_start;
...@@ -416,7 +407,7 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size) ...@@ -416,7 +407,7 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size)
ioc->avg_search[ioc->avg_idx++] = cr_start; ioc->avg_search[ioc->avg_idx++] = cr_start;
ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1; ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1;
#endif #endif
#ifdef CCIO_MAP_STATS #ifdef CCIO_COLLECT_STATS
ioc->used_pages += pages_needed; ioc->used_pages += pages_needed;
#endif #endif
/* /*
...@@ -452,7 +443,7 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped) ...@@ -452,7 +443,7 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped)
DBG_RES("%s(): res_idx: %d pages_mapped %d\n", DBG_RES("%s(): res_idx: %d pages_mapped %d\n",
__func__, res_idx, pages_mapped); __func__, res_idx, pages_mapped);
#ifdef CCIO_MAP_STATS #ifdef CCIO_COLLECT_STATS
ioc->used_pages -= pages_mapped; ioc->used_pages -= pages_mapped;
#endif #endif
...@@ -764,7 +755,7 @@ ccio_map_single(struct device *dev, void *addr, size_t size, ...@@ -764,7 +755,7 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
size = ALIGN(size + offset, IOVP_SIZE); size = ALIGN(size + offset, IOVP_SIZE);
spin_lock_irqsave(&ioc->res_lock, flags); spin_lock_irqsave(&ioc->res_lock, flags);
#ifdef CCIO_MAP_STATS #ifdef CCIO_COLLECT_STATS
ioc->msingle_calls++; ioc->msingle_calls++;
ioc->msingle_pages += size >> IOVP_SHIFT; ioc->msingle_pages += size >> IOVP_SHIFT;
#endif #endif
...@@ -828,7 +819,7 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size, ...@@ -828,7 +819,7 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
spin_lock_irqsave(&ioc->res_lock, flags); spin_lock_irqsave(&ioc->res_lock, flags);
#ifdef CCIO_MAP_STATS #ifdef CCIO_COLLECT_STATS
ioc->usingle_calls++; ioc->usingle_calls++;
ioc->usingle_pages += size >> IOVP_SHIFT; ioc->usingle_pages += size >> IOVP_SHIFT;
#endif #endif
...@@ -894,7 +885,7 @@ ccio_free_consistent(struct device *dev, size_t size, void *cpu_addr, ...@@ -894,7 +885,7 @@ ccio_free_consistent(struct device *dev, size_t size, void *cpu_addr,
*/ */
#define PIDE_FLAG 0x80000000UL #define PIDE_FLAG 0x80000000UL
#ifdef CCIO_MAP_STATS #ifdef CCIO_COLLECT_STATS
#define IOMMU_MAP_STATS #define IOMMU_MAP_STATS
#endif #endif
#include "iommu-helpers.h" #include "iommu-helpers.h"
...@@ -938,7 +929,7 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents, ...@@ -938,7 +929,7 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
spin_lock_irqsave(&ioc->res_lock, flags); spin_lock_irqsave(&ioc->res_lock, flags);
#ifdef CCIO_MAP_STATS #ifdef CCIO_COLLECT_STATS
ioc->msg_calls++; ioc->msg_calls++;
#endif #endif
...@@ -997,13 +988,13 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, ...@@ -997,13 +988,13 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
DBG_RUN_SG("%s() START %d entries, %08lx,%x\n", DBG_RUN_SG("%s() START %d entries, %08lx,%x\n",
__func__, nents, sg_virt_addr(sglist), sglist->length); __func__, nents, sg_virt_addr(sglist), sglist->length);
#ifdef CCIO_MAP_STATS #ifdef CCIO_COLLECT_STATS
ioc->usg_calls++; ioc->usg_calls++;
#endif #endif
while(sg_dma_len(sglist) && nents--) { while(sg_dma_len(sglist) && nents--) {
#ifdef CCIO_MAP_STATS #ifdef CCIO_COLLECT_STATS
ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT; ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
#endif #endif
ccio_unmap_single(dev, sg_dma_address(sglist), ccio_unmap_single(dev, sg_dma_address(sglist),
...@@ -1048,7 +1039,7 @@ static int ccio_proc_info(struct seq_file *m, void *p) ...@@ -1048,7 +1039,7 @@ static int ccio_proc_info(struct seq_file *m, void *p)
len += seq_printf(m, "IO PDIR size : %d bytes (%d entries)\n", len += seq_printf(m, "IO PDIR size : %d bytes (%d entries)\n",
total_pages * 8, total_pages); total_pages * 8, total_pages);
#ifdef CCIO_MAP_STATS #ifdef CCIO_COLLECT_STATS
len += seq_printf(m, "IO PDIR entries : %ld free %ld used (%d%%)\n", len += seq_printf(m, "IO PDIR entries : %ld free %ld used (%d%%)\n",
total_pages - ioc->used_pages, ioc->used_pages, total_pages - ioc->used_pages, ioc->used_pages,
(int)(ioc->used_pages * 100 / total_pages)); (int)(ioc->used_pages * 100 / total_pages));
...@@ -1057,7 +1048,7 @@ static int ccio_proc_info(struct seq_file *m, void *p) ...@@ -1057,7 +1048,7 @@ static int ccio_proc_info(struct seq_file *m, void *p)
len += seq_printf(m, "Resource bitmap : %d bytes (%d pages)\n", len += seq_printf(m, "Resource bitmap : %d bytes (%d pages)\n",
ioc->res_size, total_pages); ioc->res_size, total_pages);
#ifdef CCIO_SEARCH_TIME #ifdef CCIO_COLLECT_STATS
min = max = ioc->avg_search[0]; min = max = ioc->avg_search[0];
for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) { for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) {
avg += ioc->avg_search[j]; avg += ioc->avg_search[j];
...@@ -1070,7 +1061,7 @@ static int ccio_proc_info(struct seq_file *m, void *p) ...@@ -1070,7 +1061,7 @@ static int ccio_proc_info(struct seq_file *m, void *p)
len += seq_printf(m, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", len += seq_printf(m, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
min, avg, max); min, avg, max);
#endif #endif
#ifdef CCIO_MAP_STATS #ifdef CCIO_COLLECT_STATS
len += seq_printf(m, "pci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n", len += seq_printf(m, "pci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n",
ioc->msingle_calls, ioc->msingle_pages, ioc->msingle_calls, ioc->msingle_pages,
(int)((ioc->msingle_pages * 1000)/ioc->msingle_calls)); (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls));
...@@ -1088,7 +1079,7 @@ static int ccio_proc_info(struct seq_file *m, void *p) ...@@ -1088,7 +1079,7 @@ static int ccio_proc_info(struct seq_file *m, void *p)
len += seq_printf(m, "pci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n\n\n", len += seq_printf(m, "pci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n\n\n",
ioc->usg_calls, ioc->usg_pages, ioc->usg_calls, ioc->usg_pages,
(int)((ioc->usg_pages * 1000)/ioc->usg_calls)); (int)((ioc->usg_pages * 1000)/ioc->usg_calls));
#endif /* CCIO_MAP_STATS */ #endif /* CCIO_COLLECT_STATS */
ioc = ioc->next; ioc = ioc->next;
} }
......
...@@ -610,6 +610,14 @@ config RTC_DRV_RS5C313 ...@@ -610,6 +610,14 @@ config RTC_DRV_RS5C313
help help
If you say yes here you get support for the Ricoh RS5C313 RTC chips. If you say yes here you get support for the Ricoh RS5C313 RTC chips.
config RTC_DRV_PARISC
tristate "PA-RISC firmware RTC support"
depends on PARISC
help
Say Y or M here to enable RTC support on PA-RISC systems using
firmware calls. If you do not know what you are doing, you should
just say Y.
config RTC_DRV_PPC config RTC_DRV_PPC
tristate "PowerPC machine dependent RTC support" tristate "PowerPC machine dependent RTC support"
depends on PPC depends on PPC
......
...@@ -51,6 +51,7 @@ obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o ...@@ -51,6 +51,7 @@ obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
obj-$(CONFIG_RTC_DRV_PARISC) += rtc-parisc.o
obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
......
/* rtc-parisc: RTC for HP PA-RISC firmware
*
* Copyright (C) 2008 Kyle McMartin <kyle@mcmartin.ca>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/platform_device.h>
#include <asm/rtc.h>
/* as simple as can be, and no simpler. */
struct parisc_rtc {
struct rtc_device *rtc;
spinlock_t lock;
};
static int parisc_get_time(struct device *dev, struct rtc_time *tm)
{
struct parisc_rtc *p = dev_get_drvdata(dev);
unsigned long flags, ret;
spin_lock_irqsave(&p->lock, flags);
ret = get_rtc_time(tm);
spin_unlock_irqrestore(&p->lock, flags);
if (ret & RTC_BATT_BAD)
return -EOPNOTSUPP;
return 0;
}
static int parisc_set_time(struct device *dev, struct rtc_time *tm)
{
struct parisc_rtc *p = dev_get_drvdata(dev);
unsigned long flags, ret;
spin_lock_irqsave(&p->lock, flags);
ret = set_rtc_time(tm);
spin_unlock_irqrestore(&p->lock, flags);
if (ret < 0)
return -EOPNOTSUPP;
return 0;
}
static const struct rtc_class_ops parisc_rtc_ops = {
.read_time = parisc_get_time,
.set_time = parisc_set_time,
};
static int __devinit parisc_rtc_probe(struct platform_device *dev)
{
struct parisc_rtc *p;
p = kzalloc(sizeof (*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
spin_lock_init(&p->lock);
p->rtc = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops,
THIS_MODULE);
if (IS_ERR(p->rtc)) {
int err = PTR_ERR(p->rtc);
kfree(p);
return err;
}
platform_set_drvdata(dev, p);
return 0;
}
static int __devexit parisc_rtc_remove(struct platform_device *dev)
{
struct parisc_rtc *p = platform_get_drvdata(dev);
rtc_device_unregister(p->rtc);
kfree(p);
return 0;
}
static struct platform_driver parisc_rtc_driver = {
.driver = {
.name = "rtc-parisc",
.owner = THIS_MODULE,
},
.probe = parisc_rtc_probe,
.remove = __devexit_p(parisc_rtc_remove),
};
static int __init parisc_rtc_init(void)
{
return platform_driver_register(&parisc_rtc_driver);
}
static void __exit parisc_rtc_fini(void)
{
platform_driver_unregister(&parisc_rtc_driver);
}
module_init(parisc_rtc_init);
module_exit(parisc_rtc_fini);
MODULE_AUTHOR("Kyle McMartin <kyle@mcmartin.ca>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("HP PA-RISC RTC driver");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment