Commit 36eaa6e4 authored by Matthew Wilcox's avatar Matthew Wilcox Committed by Linus Torvalds

[PATCH] PA-RISC update for 2.6.0-test5

PA-RISC updates for 2.6.0-test5.

Contributions from Paul Bame, James Bottomley, Randolph Chung, Helge
Deller, Grant Grundler, LaMont Jones, Matthew Wilcox
parent 8b318c7c
......@@ -184,7 +184,7 @@ source "drivers/scsi/Kconfig"
source "drivers/md/Kconfig"
#source drivers/message/fusion/Kconfig
source drivers/message/fusion/Kconfig
#source drivers/ieee1394/Kconfig
......
......@@ -16,7 +16,7 @@
# Modified for PA-RISC Linux by Paul Lahaie, Alex deVries,
# Mike Shaver, Helge Deller and Martin K. Petersen
#
NM = sh arch/parisc/nm
ifdef CONFIG_PARISC64
CROSS_COMPILE := hppa64-linux-
UTS_MACHINE := parisc64
......
......@@ -150,24 +150,25 @@ CONFIG_CHR_DEV_SG=y
CONFIG_SCSI_LASI700=y
CONFIG_53C700_MEM_MAPPED=y
CONFIG_53C700_LE_ON_BE=y
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
CONFIG_SCSI_SYM53C8XX_2=y
CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
CONFIG_SCSI_ZALON=y
# CONFIG_SCSI_NCR53C8XX is not set
CONFIG_SCSI_SYM53C8XX=y
CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
CONFIG_SCSI_NCR53C8XX_SYNC=20
# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_SIM710 is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
......@@ -374,7 +375,6 @@ CONFIG_SERIO=y
# CONFIG_SERIO_CT82C710 is not set
# CONFIG_SERIO_PARKBD is not set
CONFIG_HP_SDC=y
CONFIG_HIL_MLC=y
#
# Input Device Drivers
......
......@@ -21,17 +21,20 @@
*/
#ifdef __LP64__
#warning Must be changed for PA64
#warning PA64 support needs more work...did first cut
#endif
#include <asm/offsets.h>
#include <asm/assembly.h>
#include <asm/signal.h>
#ifdef __LP64__
.level 2.0w
#else
.level 1.1
#endif
.text
#include <asm/assembly.h>
#include <asm/signal.h>
/* These should probably go in a header file somewhere.
* They are duplicated in kernel/wrappers.S
* Possibly we should consider consolidating these
......@@ -41,41 +44,41 @@
#ifdef __LP64__
#warning NEEDS WORK for 64-bit
#endif
stw %r3, PT_GR3(\regs)
stw %r4, PT_GR4(\regs)
stw %r5, PT_GR5(\regs)
stw %r6, PT_GR6(\regs)
stw %r7, PT_GR7(\regs)
stw %r8, PT_GR8(\regs)
stw %r9, PT_GR9(\regs)
stw %r10,PT_GR10(\regs)
stw %r11,PT_GR11(\regs)
stw %r12,PT_GR12(\regs)
stw %r13,PT_GR13(\regs)
stw %r14,PT_GR14(\regs)
stw %r15,PT_GR15(\regs)
stw %r16,PT_GR16(\regs)
stw %r17,PT_GR17(\regs)
stw %r18,PT_GR18(\regs)
STREG %r3, PT_GR3(\regs)
STREG %r4, PT_GR4(\regs)
STREG %r5, PT_GR5(\regs)
STREG %r6, PT_GR6(\regs)
STREG %r7, PT_GR7(\regs)
STREG %r8, PT_GR8(\regs)
STREG %r9, PT_GR9(\regs)
STREG %r10,PT_GR10(\regs)
STREG %r11,PT_GR11(\regs)
STREG %r12,PT_GR12(\regs)
STREG %r13,PT_GR13(\regs)
STREG %r14,PT_GR14(\regs)
STREG %r15,PT_GR15(\regs)
STREG %r16,PT_GR16(\regs)
STREG %r17,PT_GR17(\regs)
STREG %r18,PT_GR18(\regs)
.endm
.macro reg_restore regs
ldw PT_GR3(\regs), %r3
ldw PT_GR4(\regs), %r4
ldw PT_GR5(\regs), %r5
ldw PT_GR6(\regs), %r6
ldw PT_GR7(\regs), %r7
ldw PT_GR8(\regs), %r8
ldw PT_GR9(\regs), %r9
ldw PT_GR10(\regs),%r10
ldw PT_GR11(\regs),%r11
ldw PT_GR12(\regs),%r12
ldw PT_GR13(\regs),%r13
ldw PT_GR14(\regs),%r14
ldw PT_GR15(\regs),%r15
ldw PT_GR16(\regs),%r16
ldw PT_GR17(\regs),%r17
ldw PT_GR18(\regs),%r18
LDREG PT_GR3(\regs), %r3
LDREG PT_GR4(\regs), %r4
LDREG PT_GR5(\regs), %r5
LDREG PT_GR6(\regs), %r6
LDREG PT_GR7(\regs), %r7
LDREG PT_GR8(\regs), %r8
LDREG PT_GR9(\regs), %r9
LDREG PT_GR10(\regs),%r10
LDREG PT_GR11(\regs),%r11
LDREG PT_GR12(\regs),%r12
LDREG PT_GR13(\regs),%r13
LDREG PT_GR14(\regs),%r14
LDREG PT_GR15(\regs),%r15
LDREG PT_GR16(\regs),%r16
LDREG PT_GR17(\regs),%r17
LDREG PT_GR18(\regs),%r18
.endm
......@@ -88,18 +91,18 @@ hpux_fork_wrapper:
;! pointer in task
reg_save %r1
stw %r2,-20(%r30)
STREG %r2,-20(%r30)
ldo 64(%r30),%r30
stw %r2,PT_GR19(%r1) ;! save for child
stw %r30,PT_GR21(%r1) ;! save for child
STREG %r2,PT_GR19(%r1) ;! save for child
STREG %r30,PT_GR21(%r1) ;! save for child
ldw PT_GR30(%r1),%r25
mtctl %r25,%cr29
LDREG PT_GR30(%r1),%r25
mtctl %r25,%cr29
copy %r1,%r24
bl sys_clone,%r2
ldi SIGCHLD,%r26
ldw -84(%r30),%r2
LDREG -84(%r30),%r2
fork_return:
ldo -64(%r30),%r30
ldo TASK_REGS-TASK_SZ_ALGN-64(%r30),%r1 ;! get pt regs
......@@ -116,14 +119,14 @@ fork_return:
* know the difference. We can fix this later if necessary.
*/
ldo -1024(%r0),%r1
ldo -1024(%r0),%r1
comb,>>=,n %r28,%r1,fork_exit /* just let the syscall exit handle it */
or,= %r28,%r0,%r0
or,tr %r0,%r0,%r29 /* r28 <> 0, we are parent, set r29 to 0 */
ldo 1(%r0),%r29 /* r28 == 0, we are child, set r29 to 1 */
or,= %r28,%r0,%r0
or,tr %r0,%r0,%r29 /* r28 <> 0, we are parent, set r29 to 0 */
ldo 1(%r0),%r29 /* r28 == 0, we are child, set r29 to 1 */
fork_exit:
bv %r0(%r2)
bv %r0(%r2)
nop
/* Set the return value for the child */
......@@ -134,7 +137,7 @@ hpux_child_return:
nop
#endif
ldw TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
LDREG TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
b fork_return
copy %r0,%r28
......@@ -157,17 +160,17 @@ hpux_execve_wrapper:
/* Store arg0, arg1 and arg2 so that hpux_execve will find them */
stw %r26,PT_GR26(%r1)
stw %r25,PT_GR25(%r1)
stw %r24,PT_GR24(%r1)
STREG %r26,PT_GR26(%r1)
STREG %r25,PT_GR25(%r1)
STREG %r24,PT_GR24(%r1)
stw %r2,-20(%r30)
STREG %r2,-20(%r30)
ldo 64(%r30),%r30
bl hpux_execve,%r2
copy %r1,%arg0
ldo -64(%r30),%r30
ldw -20(%r30),%r2
LDREG -20(%r30),%r2
/* If exec succeeded we need to load the args */
......@@ -175,10 +178,10 @@ hpux_execve_wrapper:
comb,>>= %r28,%r1,exec_error
copy %r2,%r19
ldo -TASK_SZ_ALGN-64(%r30),%r1 ;! get task ptr
ldw TASK_PT_GR26(%r1),%r26
ldw TASK_PT_GR25(%r1),%r25
ldw TASK_PT_GR24(%r1),%r24
ldw TASK_PT_GR23(%r1),%r23
LDREG TASK_PT_GR26(%r1),%r26
LDREG TASK_PT_GR25(%r1),%r25
LDREG TASK_PT_GR24(%r1),%r24
LDREG TASK_PT_GR23(%r1),%r23
copy %r0,%r2 /* Flag to syscall_exit not to clear args */
exec_error:
......@@ -191,7 +194,7 @@ exec_error:
/* HP-UX expects pipefd's returned in r28 & r29 */
hpux_pipe_wrapper:
stw %r2,-20(%r30)
STREG %r2,-20(%r30)
ldo 64(%r30),%r30
bl hpux_pipe,%r2
ldo -56(%r30),%r26 /* pass local array to hpux_pipe */
......@@ -199,12 +202,12 @@ hpux_pipe_wrapper:
ldo -1024(%r0),%r1
comb,>>= %r28,%r1,pipe_exit /* let syscall exit handle it */
ldw -84(%r30),%r2
LDREG -84(%r30),%r2
/* if success, load fd's from stack array */
ldw -56(%r30),%r28
ldw -52(%r30),%r29
LDREG -56(%r30),%r28
LDREG -52(%r30),%r29
pipe_exit:
bv %r0(%r2)
......@@ -251,4 +254,4 @@ no_error:
hpux_unimplemented_wrapper:
b hpux_unimplemented
stw %r22,-64(%r30) /* overwrite arg8 with syscall number */
STREG %r22,-64(%r30) /* overwrite arg8 with syscall number */
......@@ -232,7 +232,8 @@ void __flush_dcache_page(struct page *page)
if (!page->mapping)
return;
/* check shared list first if it's not empty...it's usually
* the shortest */
list_for_each(l, &page->mapping->i_mmap_shared) {
struct vm_area_struct *mpnt;
unsigned long off;
......@@ -254,6 +255,33 @@ void __flush_dcache_page(struct page *page)
flush_cache_page(mpnt, mpnt->vm_start + (off << PAGE_SHIFT));
/* All user shared mappings should be equivalently mapped,
* so once we've flushed one we should be ok
*/
return;
}
/* then check private mapping list for read only shared mappings
* which are flagged by VM_MAYSHARE */
list_for_each(l, &page->mapping->i_mmap) {
struct vm_area_struct *mpnt;
unsigned long off;
mpnt = list_entry(l, struct vm_area_struct, shared);
if (mpnt->vm_mm != mm || !(mpnt->vm_flags & VM_MAYSHARE))
continue;
if (page->index < mpnt->vm_pgoff)
continue;
off = page->index - mpnt->vm_pgoff;
if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)
continue;
flush_cache_page(mpnt, mpnt->vm_start + (off << PAGE_SHIFT));
/* All user shared mappings should be equivalently mapped,
* so once we've flushed one we should be ok
*/
......
......@@ -447,7 +447,7 @@ int register_parisc_device(struct parisc_device *dev)
#define MAX_NATIVE_DEVICES 64
#define NATIVE_DEVICE_OFFSET 0x1000
#define FLEX_MASK (unsigned long)0xfffffffffffc0000
#define FLEX_MASK F_EXTEND(0xfffc0000)
#define IO_IO_LOW offsetof(struct bc_module, io_io_low)
#define IO_IO_HIGH offsetof(struct bc_module, io_io_high)
#define READ_IO_IO_LOW(dev) (unsigned long)(signed int)__raw_readl(dev->hpa + IO_IO_LOW)
......@@ -514,7 +514,7 @@ static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high,
} while(!devices_found && hpa < io_io_high);
}
#define CENTRAL_BUS_ADDR (unsigned long) 0xfffffffffff80000
#define CENTRAL_BUS_ADDR F_EXTEND(0xfff80000)
/**
* walk_central_bus - Find devices attached to the central bus
......
......@@ -842,6 +842,10 @@ int probe_irq_off(unsigned long val)
return irq_found;
}
unsigned int probe_irq_mask(unsigned long irqs)
{
return 0;
}
void __init init_IRQ(void)
{
......
......@@ -41,6 +41,13 @@
return -ENOEXEC; \
}
/* Maximum number of GOT entries. We use a long displacement ldd from
* the bottom of the table, which has a maximum signed displacement of
* 0x3fff; however, since we're only going forward, this becomes
* 0x1fff, and thus, since each GOT entry is 8 bytes long we can have
* at most 1023 entries */
#define MAX_GOTS 1023
/* three functions to determine where in the module core
* or init pieces the location is */
static inline int is_init(struct module *me, void *loc)
......@@ -300,11 +307,14 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend)
got = me->module_core + me->arch.got_offset;
for (i = 0; got[i].addr; i++)
if (got[i].addr == value)
return i * sizeof(struct got_entry);
goto out;
BUG_ON(++me->arch.got_count > me->arch.got_max);
got[i].addr = value;
out:
DEBUGP("GOT ENTRY %d[%x] val %lx\n", i, i*sizeof(struct got_entry),
value);
return i * sizeof(struct got_entry);
}
#endif /* __LP64__ */
......@@ -387,7 +397,7 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
stub->insns[2] = 0xe820d000; /* bve (%r1) */
stub->insns[3] = 0x537b0030; /* ldd 18(%dp),%dp */
stub->insns[0] |= reassemble_14(rrsel(get_got(me, value, addend),0));
stub->insns[0] |= reassemble_14(get_got(me, value, addend) & 0x3fff);
}
else
{
......@@ -516,6 +526,9 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
case R_PARISC_PCREL22F:
/* 22-bit PC relative address; only defined for pa20 */
val = get_stub(me, val, addend, 0, is_init(me, loc));
DEBUGP("STUB FOR %s loc %lx+%lx at %lx\n",
strtab + sym->st_name, (unsigned long)loc, addend,
val)
val = (val - dot - 8)/4;
CHECK_RELOC(val, 22);
*loc = (*loc & ~0x3ff1ffd) | reassemble_22(val);
......@@ -618,6 +631,9 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
val = get_stub(me, val, addend, 0,
is_init(me, loc));
}
DEBUGP("STUB FOR %s loc %lx, val %lx+%lx at %lx\n",
strtab + sym->st_name, loc, sym->st_value,
addend, val);
/* FIXME: local symbols work as long as the
* core and init pieces aren't separated too
* far. If this is ever broken, you will trip
......@@ -646,6 +662,9 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
/* 64-bit function address */
if(is_local(me, (void *)(val + addend))) {
*loc64 = get_fdesc(me, val+addend);
DEBUGP("FDESC for %s at %p points to %lx\n",
strtab + sym->st_name, *loc64,
((struct fdesc_entry *)*loc64)->addr);
} else {
/* if the symbol is not local to this
* module then val+addend is a pointer
......@@ -711,8 +730,13 @@ int module_finalize(const Elf_Ehdr *hdr,
}
}
printk("module %s: strtab %p, symhdr %p\n",
DEBUGP("module %s: strtab %p, symhdr %p\n",
me->name, strtab, symhdr);
if(me->arch.got_count > MAX_GOTS) {
printk(KERN_ERR "%s: Global Offset Table overflow (used %ld, allowed %d\n", me->name, me->arch.got_count, MAX_GOTS);
return -EINVAL;
}
/* no symbol table */
if(symhdr == NULL)
......
......@@ -37,6 +37,7 @@ EXPORT_SYMBOL(get_pci_node_path);
#include <asm/irq.h>
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(probe_irq_mask);
#include <asm/processor.h>
EXPORT_SYMBOL(kernel_thread);
......@@ -201,6 +202,9 @@ EXPORT_SYMBOL(__ashldi3);
EXPORT_SYMBOL(__lshrdi3);
EXPORT_SYMBOL(__muldi3);
asmlinkage void * __canonicalize_funcptr_for_compare(void *);
EXPORT_SYMBOL(__canonicalize_funcptr_for_compare);
#ifdef __LP64__
extern void __divdi3(void);
extern void __udivdi3(void);
......
This diff is collapsed.
......@@ -19,7 +19,6 @@
#include <linux/sched.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/version.h>
#include <asm/io.h>
#include <asm/offsets.h>
......
......@@ -123,7 +123,7 @@ save_control_regs:
nop
restore_control_regs:
load32 PA(save_cr_space + (N_SAVED_REGS * REG_SZ)), %r26
load32 PA(save_cr_space+(N_SAVED_REGS*REG_SZ)), %r26
POP_CR(%cr15, %r26)
POP_CR(%cr31, %r26)
POP_CR(%cr30, %r26)
......@@ -275,6 +275,7 @@ r64_ret:
nop
#endif
.export pc_in_user_space
.text
/* Doesn't belong here but I couldn't find a nicer spot. */
......@@ -283,3 +284,17 @@ pc_in_user_space:
bv,n 0(%rp)
nop
.export __canonicalize_funcptr_for_compare
.text
/* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html
** GCC 3.3 and later has a new function in libgcc.a for
** comparing function pointers.
*/
__canonicalize_funcptr_for_compare:
#ifdef __LP64__
bve (%r2)
#else
bv %r0(%r2)
#endif
copy %r26,%r28
......@@ -13,7 +13,6 @@
* arch/parisc/hpux/signal.c when we figure out how to do them.
*/
#include <linux/version.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
......@@ -458,6 +457,8 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
if (in_syscall) {
/* Check the return code */
switch (regs->gr[28]) {
case -ERESTART_RESTARTBLOCK:
current_thread_info()->restart_block.fn = do_no_restart_syscall;
case -ERESTARTNOHAND:
DBG(("ERESTARTNOHAND: returning -EINTR\n"));
regs->gr[28] = -EINTR;
......@@ -495,7 +496,8 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
/* Did we come from a system call? */
if (in_syscall) {
/* Restart the system call - no handlers present */
if (regs->gr[28] == -ERESTARTNOHAND ||
if (regs->gr[28] == -ERESTART_RESTARTBLOCK ||
regs->gr[28] == -ERESTARTNOHAND ||
regs->gr[28] == -ERESTARTSYS ||
regs->gr[28] == -ERESTARTNOINTR) {
/* Hooray for delayed branching. We don't
......
......@@ -30,8 +30,6 @@ static unsigned long get_unshared_area(unsigned long addr, unsigned long len)
{
struct vm_area_struct *vma;
if (!addr)
addr = TASK_UNMAPPED_BASE;
addr = PAGE_ALIGN(addr);
for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
......@@ -46,17 +44,38 @@ static unsigned long get_unshared_area(unsigned long addr, unsigned long len)
#define DCACHE_ALIGN(addr) (((addr) + (SHMLBA - 1)) &~ (SHMLBA - 1))
static unsigned long get_shared_area(struct inode *inode, unsigned long addr,
unsigned long len, unsigned long pgoff)
/*
* We need to know the offset to use. Old scheme was to look for
* existing mapping and use the same offset. New scheme is to use the
* address of the kernel data structure as the seed for the offset.
* We'll see how that works...
*/
#if 0
static int get_offset(struct address_space *mapping)
{
struct vm_area_struct *vma = list_entry(mapping->i_mmap_shared.next,
struct vm_area_struct, shared);
return (vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT)) &
(SHMLBA - 1);
}
#else
/* The mapping is cacheline aligned, so there's no information in the bottom
* few bits of the address. We're looking for 10 bits (4MB / 4k), so let's
* drop the bottom 8 bits and use bits 8-17.
*/
static int get_offset(struct address_space *mapping)
{
struct vm_area_struct *vma, *first_vma;
int offset;
int offset = (int) mapping << (PAGE_SHIFT - 8);
return offset & 0x3FF000;
}
#endif
first_vma = list_entry(inode->i_mapping->i_mmap_shared.next, struct vm_area_struct, shared);
offset = (first_vma->vm_start + ((pgoff - first_vma->vm_pgoff) << PAGE_SHIFT)) & (SHMLBA - 1);
static unsigned long get_shared_area(struct address_space *mapping,
unsigned long addr, unsigned long len, unsigned long pgoff)
{
struct vm_area_struct *vma;
int offset = get_offset(mapping);
if (!addr)
addr = TASK_UNMAPPED_BASE;
addr = DCACHE_ALIGN(addr - offset) + offset;
for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
......@@ -74,17 +93,17 @@ static unsigned long get_shared_area(struct inode *inode, unsigned long addr,
unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags)
{
struct inode *inode = NULL;
struct inode *inode;
if (len > TASK_SIZE)
return -ENOMEM;
if (!addr)
addr = TASK_UNMAPPED_BASE;
if (filp) {
inode = filp->f_dentry->d_inode;
}
inode = filp ? filp->f_dentry->d_inode : NULL;
if (inode && (flags & MAP_SHARED) && (!list_empty(&inode->i_mapping->i_mmap_shared))) {
addr = get_shared_area(inode, addr, len, pgoff);
if (inode && (flags & MAP_SHARED)) {
addr = get_shared_area(inode->i_mapping, addr, len, pgoff);
} else {
addr = get_unshared_area(addr, len);
}
......@@ -185,6 +204,7 @@ extern asmlinkage ssize_t sys_pread64(unsigned int fd, char *buf,
size_t count, loff_t pos);
extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char *buf,
size_t count, loff_t pos);
extern asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count);
asmlinkage ssize_t parisc_pread64(unsigned int fd, char *buf, size_t count,
unsigned int high, unsigned int low)
......@@ -198,6 +218,11 @@ asmlinkage ssize_t parisc_pwrite64(unsigned int fd, const char *buf,
return sys_pwrite64(fd, buf, count, (loff_t)high << 32 | low);
}
asmlinkage ssize_t parisc_readahead(int fd, unsigned int high, unsigned int low,
size_t count)
{
return sys_readahead(fd, (loff_t)high << 32 | low, count);
}
/*
* FIXME, please remove this crap as soon as possible
......@@ -271,7 +296,7 @@ static int copyout_broken_shmid64(struct broken_shmid64_ds *buf, struct shmid64_
tbuf.shm_cpid = sbuf->shm_cpid;
tbuf.shm_lpid = sbuf->shm_lpid;
tbuf.shm_nattch = sbuf->shm_nattch;
return copy_to_user(buf, &tbuf, sizeof tbuf);
return copy_to_user(buf, &tbuf, sizeof tbuf) ? -EFAULT : 0;
}
int sys_msgctl_broken(int msqid, int cmd, struct msqid_ds *buf)
......
......@@ -46,6 +46,7 @@
#include <linux/namei.h>
#include <linux/vfs.h>
#include <linux/ptrace.h>
#include <linux/swap.h>
#include <asm/types.h>
#include <asm/uaccess.h>
......@@ -373,18 +374,16 @@ put_compat_timeval(struct compat_timeval *u, struct timeval *t)
return copy_to_user(u, &t32, sizeof t32);
}
static int
get_compat_timeval(struct compat_timeval *u, struct timeval *t)
static inline long get_ts32(struct timespec *o, struct compat_timeval *i)
{
int err;
struct compat_timeval t32;
long usec;
if ((err = copy_from_user(&t32, u, sizeof t32)) == 0)
{
t->tv_sec = t32.tv_sec;
t->tv_usec = t32.tv_usec;
}
return err;
if (__get_user(o->tv_sec, &i->tv_sec))
return -EFAULT;
if (__get_user(usec, &i->tv_usec))
return -EFAULT;
o->tv_nsec = usec * 1000;
return 0;
}
asmlinkage long sys32_time(compat_time_t *tloc)
......@@ -418,23 +417,22 @@ sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
return 0;
}
asmlinkage int
sys32_settimeofday(struct compat_timespec *tv, struct timezone *tz)
asmlinkage
int sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
{
struct timeval ktv;
struct timezone ktz;
extern int do_sys_settimeofday(struct timespec *tv, struct timezone *tz);
struct timespec kts;
struct timezone ktz;
if (tv) {
if (get_compat_timeval(tv, &ktv))
return -EFAULT;
}
if (tz) {
if (copy_from_user(&ktz, tz, sizeof(ktz)))
return -EFAULT;
}
if (tv) {
if (get_ts32(&kts, tv))
return -EFAULT;
}
if (tz) {
if (copy_from_user(&ktz, tz, sizeof(ktz)))
return -EFAULT;
}
return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
}
int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
......@@ -1089,6 +1087,27 @@ asmlinkage long sys32_msgrcv(int msqid,
return err;
}
extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count)
{
mm_segment_t old_fs = get_fs();
int ret;
off_t of;
if (offset && get_user(of, offset))
return -EFAULT;
set_fs(KERNEL_DS);
ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
set_fs(old_fs);
if (offset && put_user(of, offset))
return -EFAULT;
return ret;
}
/* EXPORT/UNEXPORT */
struct nfsctl_export32 {
char ex_client[NFSCLNT_IDMAX+1];
......
......@@ -483,7 +483,7 @@ sys_call_table:
ENTRY_SAME(madvise)
ENTRY_SAME(clone_wrapper) /* 120 */
ENTRY_SAME(setdomainname)
ENTRY_SAME(sendfile)
ENTRY_DIFF(sendfile)
/* struct sockaddr... */
ENTRY_SAME(recvfrom)
/* struct timex contains longs */
......@@ -592,7 +592,7 @@ sys_call_table:
ENTRY_SAME(ni_syscall)
ENTRY_SAME(ni_syscall) /* 205 */
ENTRY_SAME(gettid)
ENTRY_SAME(readahead)
ENTRY_OURS(readahead)
ENTRY_SAME(ni_syscall) /* tkill */
ENTRY_SAME(sendfile64)
......
......@@ -221,6 +221,8 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
return;
}
oops_in_progress = 1;
/* Amuse the user in a SPARC fashion */
printk(
" _______________________________ \n"
......@@ -414,6 +416,8 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
{
static spinlock_t terminate_lock = SPIN_LOCK_UNLOCKED;
oops_in_progress = 1;
set_eiem(0);
local_irq_disable();
spin_lock(&terminate_lock);
......
#!/bin/sh
##
# Hack to have an nm which removes the local symbols. We also rely
# on this nm being hidden out of the ordinarily executable path
##
${CROSS_COMPILE}nm $* | grep -v '.LC*[0-9]*$'
......@@ -76,8 +76,6 @@ asp_init_chip(struct parisc_device *dev)
printk(KERN_INFO "%s version %d at 0x%lx found.\n",
asp->name, asp->version, dev->hpa);
snprintf(dev->dev.name, sizeof(dev->dev.name), "%s version %d",
asp->name, asp->version);
/* the IRQ ASP should use */
ret = -EBUSY;
......
......@@ -129,6 +129,92 @@ struct ioa_registers {
volatile uint32_t io_io_high; /* Offset 15 */
};
/*
** IOA Registers
** -------------
**
** Runway IO_CONTROL Register (+0x38)
**
** The Runway IO_CONTROL register controls the forwarding of transactions.
**
** | 0 ... 13 | 14 15 | 16 ... 21 | 22 | 23 24 | 25 ... 31 |
** | HV | TLB | reserved | HV | mode | reserved |
**
** o mode field indicates the address translation of transactions
** forwarded from Runway to GSC+:
** Mode Name Value Definition
** Off (default) 0 Opaque to matching addresses.
** Include 1 Transparent for matching addresses.
** Peek 3 Map matching addresses.
**
** + "Off" mode: Runway transactions which match the I/O range
** specified by the IO_IO_LOW/IO_IO_HIGH registers will be ignored.
** + "Include" mode: all addresses within the I/O range specified
** by the IO_IO_LOW and IO_IO_HIGH registers are transparently
** forwarded. This is the I/O Adapter's normal operating mode.
** + "Peek" mode: used during system configuration to initialize the
** GSC+ bus. Runway Write_Shorts in the address range specified by
** IO_IO_LOW and IO_IO_HIGH are forwarded through the I/O Adapter
** *AND* the GSC+ address is remapped to the Broadcast Physical
** Address space by setting the 14 high order address bits of the
** 32 bit GSC+ address to ones.
**
** o TLB field affects transactions which are forwarded from GSC+ to Runway.
** "Real" mode is the poweron default.
**
** TLB Mode Value Description
** Real 0 No TLB translation. Address is directly mapped and the
** virtual address is composed of selected physical bits.
** Error 1 Software fills the TLB manually.
** Normal 2 IOA fetches IO TLB misses from IO PDIR (in host memory).
**
**
** IO_IO_LOW_HV +0x60 (HV dependent)
** IO_IO_HIGH_HV +0x64 (HV dependent)
** IO_IO_LOW +0x78 (Architected register)
** IO_IO_HIGH +0x7c (Architected register)
**
** IO_IO_LOW and IO_IO_HIGH set the lower and upper bounds of the
** I/O Adapter address space, respectively.
**
** 0 ... 7 | 8 ... 15 | 16 ... 31 |
** 11111111 | 11111111 | address |
**
** Each LOW/HIGH pair describes a disjoint address space region.
** (2 per GSC+ port). Each incoming Runway transaction address is compared
** with both sets of LOW/HIGH registers. If the address is in the range
** greater than or equal to IO_IO_LOW and less than IO_IO_HIGH the transaction
** for forwarded to the respective GSC+ bus.
** Specify IO_IO_LOW equal to or greater than IO_IO_HIGH to avoid specifying
** an address space region.
**
** In order for a Runway address to reside within GSC+ extended address space:
** Runway Address [0:7] must identically compare to 8'b11111111
** Runway Address [8:11] must be equal to IO_IO_LOW(_HV)[16:19]
** Runway Address [12:23] must be greater than or equal to
** IO_IO_LOW(_HV)[20:31] and less than IO_IO_HIGH(_HV)[20:31].
** Runway Address [24:39] is not used in the comparison.
**
** When the Runway transaction is forwarded to GSC+, the GSC+ address is
** as follows:
** GSC+ Address[0:3] 4'b1111
** GSC+ Address[4:29] Runway Address[12:37]
** GSC+ Address[30:31] 2'b00
**
** All 4 Low/High registers must be initialized (by PDC) once the lower bus
** is interrogated and address space is defined. The operating system will
** modify the architectural IO_IO_LOW and IO_IO_HIGH registers following
** the PDC initialization. However, the hardware version dependent IO_IO_LOW
** and IO_IO_HIGH registers should not be subsequently altered by the OS.
**
** Writes to both sets of registers will take effect immediately, bypassing
** the queues, which ensures that subsequent Runway transactions are checked
** against the updated bounds values. However reads are queued, introducing
** the possibility of a read being bypassed by a subsequent write to the same
** register. This sequence can be avoided by having software wait for read
** returns before issuing subsequent writes.
*/
struct ioc {
struct ioa_registers *ioc_hpa; /* I/O MMU base address */
u8 *res_map; /* resource map, bit == pdir entry */
......@@ -1448,13 +1534,74 @@ static void __init ccio_init_resources(struct ioc *ioc)
(unsigned long)&ioc->ioc_hpa->io_io_low_hv);
}
static void expand_ioc_area(struct ioc *ioc, unsigned long size,
unsigned long min, unsigned long max, unsigned long align)
static int expand_resource(struct resource *res, unsigned long size,
unsigned long align)
{
#ifdef NASTY_HACK_FOR_K_CLASS
__raw_writel(0xfffff600, (unsigned long)&(ioc->ioc_hpa->io_io_high));
ioc->mmio_region[0].end = 0xf5ffffff;
#endif
struct resource *temp_res;
unsigned long start = res->start;
unsigned long end ;
/* see if we can expand above */
end = (res->end + size + align - 1) & ~(align - 1);;
temp_res = __request_region(res->parent, res->end, end - res->end,
"expansion");
if(!temp_res) {
/* now try below */
start = ((res->start - size + align) & ~(align - 1)) - align;
end = res->end;
temp_res = __request_region(res->parent, start, size,
"expansion");
if(!temp_res) {
return -ENOMEM;
}
}
release_resource(temp_res);
temp_res = res->parent;
release_resource(res);
res->start = start;
res->end = end;
/* This could be caused by some sort of race. Basically, if
* this tripped something stole the region we just reserved
* and then released to check for expansion */
BUG_ON(request_resource(temp_res, res) != 0);
return 0;
}
static void expand_ioc_area(struct resource *parent, struct ioc *ioc,
unsigned long size, unsigned long min,
unsigned long max, unsigned long align)
{
if(ioc == NULL)
/* no IOC, so nothing to expand */
return;
if (expand_resource(parent, size, align) != 0) {
printk(KERN_ERR "Unable to expand %s window by 0x%lx\n",
parent->name, size);
return;
}
/* OK, we have the memory, now expand the window */
if (parent == &ioc->mmio_region[0]) {
__raw_writel(((parent->start)>>16) | 0xffff0000,
(unsigned long)&(ioc->ioc_hpa->io_io_low));
__raw_writel(((parent->end)>>16) | 0xffff0000,
(unsigned long)&(ioc->ioc_hpa->io_io_high));
} else if (parent == &ioc->mmio_region[1]) {
__raw_writel(((parent->start)>>16) | 0xffff0000,
(unsigned long)&(ioc->ioc_hpa->io_io_low_hv));
__raw_writel(((parent->end)>>16) | 0xffff0000,
(unsigned long)&(ioc->ioc_hpa->io_io_high_hv));
} else {
/* This should be impossible. It means
* expand_ioc_area got called with a resource that
* didn't belong to the ioc
*/
BUG();
}
}
static struct resource *ccio_get_resource(struct ioc* ioc,
......@@ -1488,7 +1635,7 @@ int ccio_allocate_resource(const struct parisc_device *dev,
alignf_data))
return 0;
expand_ioc_area(ioc, size, min, max, align);
expand_ioc_area(parent, ioc, size, min, max, align);
return allocate_resource(parent, res, size, min, max, align, alignf,
alignf_data);
}
......@@ -1522,7 +1669,6 @@ static int ccio_probe(struct parisc_device *dev)
memset(ioc, 0, sizeof(struct ioc));
ioc->name = dev->id.hversion == U2_IOA_RUNWAY ? "U2" : "UTurn";
strlcpy(dev->dev.name, ioc->name, sizeof(dev->dev.name));
printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, dev->hpa);
......
......@@ -401,23 +401,7 @@ dino_isr(int irq, void *intr_dev, struct pt_regs *regs)
{
int irq;
/*
* Perform a binary search on set bits.
* `Less than Fatal' and PS2 interrupts aren't supported.
*/
if (mask & 0xf) {
if (mask & 0x3) {
irq = (mask & 0x1) ? 0 : 1; /* PCI INT A, B */
} else {
irq = (mask & 0x4) ? 2 : 3; /* PCI INT C, D */
}
} else {
if (mask & 0x30) {
irq = (mask & 0x10) ? 4 : 5; /* PCI INT E, F */
} else {
irq = (mask & 0x40) ? 6 : 10; /* GSC, RS232 */
}
}
irq = __ffs(mask);
mask &= ~(1<<irq);
......@@ -440,7 +424,7 @@ dino_isr(int irq, void *intr_dev, struct pt_regs *regs)
if (mask) {
if (--ilr_loop > 0)
goto ilr_again;
printk("Dino %lx: stuck interrupt %d\n", dino_dev->hba.base_addr, mask);
printk(KERN_ERR "Dino %lx: stuck interrupt %d\n", dino_dev->hba.base_addr, mask);
return IRQ_NONE;
}
return IRQ_HANDLED;
......@@ -479,15 +463,35 @@ dino_card_setup(struct pci_bus *bus, unsigned long base_addr)
int i;
struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->dev));
struct resource *res;
char name[128];
int size;
res = &dino_dev->hba.lmmio_space;
res->flags = IORESOURCE_MEM;
size = snprintf(name, sizeof(name), "Dino LMMIO (%s)", bus->dev->bus_id);
res->name = kmalloc(size+1, GFP_KERNEL);
if(res->name)
strcpy((char *)res->name, name);
else
res->name = dino_dev->hba.lmmio_space.name;
if (ccio_allocate_resource(dino_dev->hba.dev, res, _8MB,
(unsigned long) 0xfffffffff0000000UL | _8MB,
0xffffffffffffffffUL &~ _8MB, _8MB,
F_EXTEND(0xf0000000UL) | _8MB,
F_EXTEND(0xffffffffUL) &~ _8MB, _8MB,
NULL, NULL) < 0) {
printk(KERN_WARNING "Dino: Failed to allocate memory region\n");
struct list_head *ln, *tmp_ln;
printk(KERN_ERR "Dino: cannot attach bus %s\n",
bus->dev->bus_id);
/* kill the bus, we can't do anything with it */
list_for_each_safe(ln, tmp_ln, &bus->devices) {
struct pci_dev *dev = pci_dev_b(ln);
list_del(&dev->global_list);
list_del(&dev->bus_list);
}
return;
}
bus->resource[1] = res;
......@@ -495,9 +499,11 @@ dino_card_setup(struct pci_bus *bus, unsigned long base_addr)
/* Now tell dino what range it has */
for (i = 1; i < 31; i++) {
if (res->start == (0xfffffffff0000000UL | i * _8MB))
if (res->start == F_EXTEND(0xf0000000UL | (i * _8MB)))
break;
}
DBG("DINO GSC WRITE i=%d, start=%lx, dino addr = %lx\n",
i, res->start, base_addr + DINO_IO_ADDR_EN);
gsc_writel(1 << i, base_addr + DINO_IO_ADDR_EN);
pci_bus_assign_resources(bus);
......@@ -521,7 +527,7 @@ dino_card_fixup(struct pci_dev *dev)
** Set Latency Timer to 0xff (not a shared bus)
** Set CACHELINE_SIZE.
*/
dino_cfg_write(dev->bus, dev->devfn, PCI_CACHE_LINE_SIZE, 16, 0xff00 | L1_CACHE_BYTES/4);
dino_cfg_write(dev->bus, dev->devfn, PCI_CACHE_LINE_SIZE, 2, 0xff00 | L1_CACHE_BYTES/4);
/*
** Program INT_LINE for card-mode devices.
......@@ -532,13 +538,13 @@ dino_card_fixup(struct pci_dev *dev)
** "-1" converts INTA-D (1-4) to PCIINTA-D (0-3) range.
** The additional "-1" adjusts for skewing the IRQ<->slot.
*/
dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 8, &irq_pin);
dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 1, &irq_pin);
dev->irq = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ;
/* Shouldn't really need to do this but it's in case someone tries
** to bypass PCI services and look at the card themselves.
*/
dino_cfg_write(dev->bus, dev->devfn, PCI_INTERRUPT_LINE, 8, dev->irq);
dino_cfg_write(dev->bus, dev->devfn, PCI_INTERRUPT_LINE, 1, dev->irq);
}
......@@ -585,8 +591,8 @@ dino_fixup_bus(struct pci_bus *bus)
#ifdef __LP64__
/* Sign Extend MMIO addresses */
else if (res->flags & IORESOURCE_MEM) {
res->start |= 0xffffffff00000000UL;
res->end |= 0xffffffff00000000UL;
res->start |= F_EXTEND(0UL);
res->end |= F_EXTEND(0UL);
}
#endif
}
......@@ -789,8 +795,8 @@ static int __init dino_common_init(struct parisc_device *dev,
return 0;
}
#define CUJO_RAVEN_ADDR 0xfffffffff1000000UL
#define CUJO_FIREHAWK_ADDR 0xfffffffff1604000UL
#define CUJO_RAVEN_ADDR F_EXTEND(0xf1000000UL)
#define CUJO_FIREHAWK_ADDR F_EXTEND(0xf1604000UL)
#define CUJO_RAVEN_BADPAGE 0x01003000UL
#define CUJO_FIREHAWK_BADPAGE 0x01607000UL
......@@ -818,9 +824,16 @@ dino_driver_callback(struct parisc_device *dev)
{
struct dino_device *dino_dev; // Dino specific control struct
const char *version = "unknown";
const char *name = "Dino";
const int name_len = 32;
char *name;
int is_cujo = 0;
name = kmalloc(name_len, GFP_KERNEL);
if(name)
snprintf(name, name_len, "Dino %s", dev->dev.bus_id);
else
name = "Dino";
if (is_card_dino(&dev->id)) {
version = "3.x (card mode)";
} else {
......@@ -838,8 +851,6 @@ dino_driver_callback(struct parisc_device *dev)
}
printk("%s version %s found at 0x%lx\n", name, version, dev->hpa);
snprintf(dev->dev.name, sizeof(dev->dev.name),
"%s version %s", name, version);
if (!request_mem_region(dev->hpa, PAGE_SIZE, name)) {
printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%ld)!\n",
......
......@@ -327,14 +327,13 @@ static int __devinit eisa_probe(struct parisc_device *dev)
printk(KERN_INFO "%s EISA Adapter found at 0x%08lx\n",
name, dev->hpa);
snprintf(dev->dev.name, sizeof(dev->dev.name), "%s EISA", name);
eisa_dev.hba.dev = dev;
eisa_dev.hba.iommu = ccio_get_iommu(dev);
eisa_dev.hba.lmmio_space.name = "EISA";
eisa_dev.hba.lmmio_space.start = (unsigned long) 0xfffffffffc000000;
eisa_dev.hba.lmmio_space.end = (unsigned long) 0xffffffffffbfffff;
eisa_dev.hba.lmmio_space.start = F_EXTEND(0xfc000000);
eisa_dev.hba.lmmio_space.end = F_EXTEND(0xffbfffff);
eisa_dev.hba.lmmio_space.flags = IORESOURCE_MEM;
result = ccio_request_resource(dev, &eisa_dev.hba.lmmio_space);
if (result < 0) {
......
......@@ -70,7 +70,6 @@ static int hppb_probe(struct parisc_device *dev)
card = card->next;
}
printk(KERN_INFO "Found GeckoBoa at 0x%lx\n", dev->hpa);
snprintf(dev->dev.name, sizeof(dev->dev.name), "GeckoBoa");
card->hpa = dev->hpa;
card->mmio_region.name = "HP-PB Bus";
......
......@@ -643,7 +643,7 @@ iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
if (NULL == isi) {
printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n",
pcidev->dev.name);
pci_name(pcidev));
return(-1);
}
......
......@@ -185,8 +185,6 @@ lasi_init_chip(struct parisc_device *dev)
lasi->version = gsc_readl(lasi->hpa + LASI_VER) & 0xf;
printk(KERN_INFO "%s version %d at 0x%lx found.\n",
lasi->name, lasi->version, lasi->hpa);
snprintf(dev->dev.name, sizeof(dev->dev.name), "%s version %d",
lasi->name, lasi->version);
/* initialize the chassis LEDs really early */
lasi_led_init(lasi->hpa);
......
......@@ -782,7 +782,7 @@ lba_fixup_bus(struct pci_bus *bus)
int i;
struct pci_dev *dev = pci_dev_b(ln);
DBG("lba_fixup_bus() %s\n", dev->name);
DBG("lba_fixup_bus() %s\n", pci_name(dev));
/* Virtualize Device/Bridge Resources. */
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
......@@ -1358,8 +1358,6 @@ lba_driver_callback(struct parisc_device *dev)
printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
MODULE_NAME, version, func_class & 0xf, dev->hpa);
snprintf(dev->dev.name, sizeof(dev->dev.name), "%s version %s",
MODULE_NAME, version);
/* Just in case we find some prototypes... */
if (func_class < 2) {
......
......@@ -91,7 +91,7 @@ struct pdc_chassis_lcd_info_ret_block {
/* LCD_CMD and LCD_DATA for KittyHawk machines */
#define KITTYHAWK_LCD_CMD (0xfffffffff0190000UL) /* 64bit-ready */
#define KITTYHAWK_LCD_CMD F_EXTEND(0xf0190000UL) /* 64bit-ready */
#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD+1)
/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's
......
......@@ -1978,8 +1978,6 @@ sba_driver_callback(struct parisc_device *dev)
printk(KERN_INFO "%s found %s at 0x%lx\n",
MODULE_NAME, version, dev->hpa);
snprintf(dev->dev.name, sizeof(dev->dev.name), "%s version %s",
MODULE_NAME, version);
#ifdef DEBUG_SBA_INIT
sba_dump_tlb(dev->hpa);
......
......@@ -83,8 +83,6 @@ wax_init_chip(struct parisc_device *dev)
wax->version = 0; /* gsc_readb(wax->hpa+WAX_VER); */
printk(KERN_INFO "%s at 0x%lx found.\n", wax->name, wax->hpa);
snprintf(dev->dev.name, sizeof(dev->dev.name), "%s version %d",
wax->name, wax->version);
/* Stop wax hissing for a bit */
wax_init_irq(wax);
......
......@@ -49,27 +49,14 @@ extern spinlock_t __atomic_hash[ATOMIC_HASH_SIZE];
* Cache-line alignment would conflict with, for example, linux/module.h
*/
typedef struct {
volatile int counter;
} atomic_t;
typedef struct { volatile long counter; } atomic_t;
/*
** xchg/cmpxchg moved from asm/system.h - ggg
*/
#if 1
/* This should get optimized out since it's never called.
** Or get a link error if xchg is used "wrong".
*/
extern void __xchg_called_with_bad_pointer(void);
#else
static inline void __xchg_called_with_bad_pointer(void)
{
extern void panic(const char * fmt, ...);
panic("xchg called with bad pointer");
}
#endif
/* __xchg32/64 defined in arch/parisc/lib/bitops.c */
extern unsigned long __xchg8(char, char *);
......
......@@ -203,55 +203,102 @@ static __inline__ int test_bit(int nr, const void *address)
return !!(*addr & mask);
}
extern __inline__ unsigned long ffz(unsigned long word)
{
unsigned long result;
result = 0;
while (word & 1) {
result++;
word >>= 1;
}
return result;
}
#ifdef __KERNEL__
/**
* __ffs - find first bit in word.
* __ffs - find first bit in word. returns 0 to "BITS_PER_LONG-1".
* @word: The word to search
*
* Undefined if no bit exists, so code should check against 0 first.
* __ffs() return is undefined if no bit is set.
*
* 32-bit fast __ffs by LaMont Jones "lamont At hp com".
* 64-bit enhancement by Grant Grundler "grundler At parisc-linux org".
* (with help from willy/jejb to get the semantics right)
*
* This algorithm avoids branches by making use of nullification.
* One side effect of "extr" instructions is it sets PSW[N] bit.
* How PSW[N] (nullify next insn) gets set is determined by the
* "condition" field (eg "<>" or "TR" below) in the extr* insn.
* Only the 1st and one of either the 2cd or 3rd insn will get executed.
* Each set of 3 insn will get executed in 2 cycles on PA8x00 vs 16 or so
* cycles for each mispredicted branch.
*/
static __inline__ unsigned long __ffs(unsigned long word)
{
unsigned long result = 0;
while (!(word & 1UL)) {
result++;
word >>= 1;
}
return result;
static __inline__ unsigned long __ffs(unsigned long x)
{
unsigned long ret;
__asm__(
#if BITS_PER_LONG > 32
" ldi 63,%1\n"
" extrd,u,*<> %0,63,32,%%r0\n"
" extrd,u,*TR %0,31,32,%0\n"
" addi -32,%1,%1\n"
#else
" ldi 31,%1\n"
#endif
" extru,<> %0,31,16,%%r0\n"
" extru,TR %0,15,16,%0\n"
" addi -16,%1,%1\n"
" extru,<> %0,31,8,%%r0\n"
" extru,TR %0,23,8,%0\n"
" addi -8,%1,%1\n"
" extru,<> %0,31,4,%%r0\n"
" extru,TR %0,27,4,%0\n"
" addi -4,%1,%1\n"
" extru,<> %0,31,2,%%r0\n"
" extru,TR %0,29,2,%0\n"
" addi -2,%1,%1\n"
" extru,= %0,31,1,%%r0\n"
" addi -1,%1,%1\n"
: "+r" (x), "=r" (ret) );
return ret;
}
/* Undefined if no bit is zero. */
#define ffz(x) __ffs(~x)
/*
* ffs: find first bit set. This is defined the same way as
* the libc and compiler builtin ffs routines, therefore
* differs in spirit from the above ffz (man ffs).
* ffs: find first bit set. returns 1 to BITS_PER_LONG or 0 (if none set)
* This is defined the same way as the libc and compiler builtin
* ffs routines, therefore differs in spirit from the above ffz (man ffs).
*/
static __inline__ int ffs(int x)
{
if (!x)
return 0;
return __ffs((unsigned long)x);
return x ? (__ffs((unsigned long)x) + 1) : 0;
}
/*
* fls: find last bit set.
* fls: find last (most significant) bit set.
* fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
#define fls(x) generic_fls(x)
static __inline__ int fls(int x)
{
int ret;
if (!x)
return 0;
__asm__(
" ldi 1,%1\n"
" extru,<> %0,15,16,%%r0\n"
" zdep,TR %0,15,16,%0\n" /* xxxx0000 */
" addi 16,%1,%1\n"
" extru,<> %0,7,8,%%r0\n"
" zdep,TR %0,23,24,%0\n" /* xx000000 */
" addi 8,%1,%1\n"
" extru,<> %0,3,4,%%r0\n"
" zdep,TR %0,27,28,%0\n" /* x0000000 */
" addi 4,%1,%1\n"
" extru,<> %0,1,2,%%r0\n"
" zdep,TR %0,29,30,%0\n" /* y0000000 (y&3 = 0 */
" addi 2,%1,%1\n"
" extru,= %0,0,1,%%r0\n"
" addi 1,%1,%1\n" /* if y & 8, add 1 */
: "+r" (x), "=r" (ret) );
return ret;
}
/*
* hweightN: returns the hamming weight (i.e. the number
......
......@@ -5,6 +5,25 @@
#ifdef __GNUC__
static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
{
__asm__("dep %0, 15, 8, %0\n\t" /* deposit 00ab -> 0bab */
"shd %%r0, %0, 8, %0" /* shift 000000ab -> 00ba */
: "=r" (x)
: "0" (x));
return x;
}
static __inline__ __const__ __u32 ___arch__swab24(__u32 x)
{
__asm__("shd %0, %0, 8, %0\n\t" /* shift xabcxabc -> cxab */
"dep %0, 15, 8, %0\n\t" /* deposit cxab -> cbab */
"shd %%r0, %0, 8, %0" /* shift 0000cbab -> 0cba */
: "=r" (x)
: "0" (x));
return x;
}
static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
{
unsigned int temp;
......@@ -39,34 +58,21 @@ static __inline__ __const__ __u64 ___arch__swab64(__u64 x) {
return x;
}
#define __arch__swab64(x) ___arch__swab64(x)
#else
#define __BYTEORDER_HAS_U64__
#elif !defined(__STRICT_ANSI__)
static __inline__ __const__ __u64 ___arch__swab64(__u64 x)
{
__u32 t1 = (__u32) x;
__u32 t2 = (__u32) ((x) >> 32);
___arch__swab32(t1);
___arch__swab32(t2);
return (((__u64) t1 << 32) + ((__u64) t2));
__u32 t1 = ___arch__swab32((__u32) x);
__u32 t2 = ___arch__swab32((__u32) (x >> 32));
return (((__u64) t1 << 32) | t2);
}
#define __arch__swab64(x) ___arch__swab64(x)
#define __BYTEORDER_HAS_U64__
#endif
static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
{
__asm__("dep %0, 15, 8, %0\n\t" /* deposit 00ab -> 0bab */
"shd %r0, %0, 8, %0" /* shift 000000ab -> 00ba */
: "=r" (x)
: "0" (x));
return x;
}
#define __arch__swab32(x) ___arch__swab32(x)
#define __arch__swab16(x) ___arch__swab16(x)
#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
# define __BYTEORDER_HAS_U64__
# define __SWAB_64_THRU_32__
#endif
#define __arch__swab24(x) ___arch__swab24(x)
#define __arch__swab32(x) ___arch__swab32(x)
#endif /* __GNUC__ */
......
......@@ -78,8 +78,9 @@ static inline void flush_dcache_page(struct page *page)
#define flush_icache_range(s,e) do { flush_kernel_dcache_range_asm(s,e); flush_kernel_icache_range_asm(s,e); } while (0)
#define flush_icache_user_range(vma, page, addr, len) \
flush_icache_page((vma), (page))
#define flush_icache_user_range(vma, page, addr, len) do { \
flush_user_dcache_range(addr, addr + len); \
flush_user_icache_range(addr, addr + len); } while (0)
static inline void flush_cache_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
......
......@@ -283,6 +283,7 @@ struct pt_regs; /* forward declaration... */
*/
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_PARISC
#define ELF_OSABI ELFOSABI_LINUX
/* %r23 is set by ld.so to a pointer to a function which might be
registered using atexit. This provides a mean for the dynamic
......
#ifndef _ASM_HIL_H
#define _ASM_HIL_H
/*
* linux/asm-parisc/hil.h
*
* (c) 1999 Matthew Wilcox
*/
extern unsigned long hil_base; /* declared in drivers/parisc/hil.c */
extern unsigned int hil_irq;
#define HILBASE hil_base /* 0xf0821000 (old) or 0xf0201000 (new) */
#define HIL_DATA 0x800
#define HIL_CMD 0x801
#define HIL_IRQ hil_irq
#define hil_busy() (gsc_readb(HILBASE + HIL_CMD) & HIL_BUSY)
#define hil_data_available() (gsc_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
#define hil_status() (gsc_readb(HILBASE + HIL_CMD))
#define hil_command(x) do { gsc_writeb((x), HILBASE + HIL_CMD); } while (0)
#define hil_read_data() (gsc_readb(HILBASE + HIL_DATA))
#define hil_write_data(x) do { gsc_writeb((x), HILBASE + HIL_DATA); } while (0)
#endif
......@@ -291,4 +291,11 @@ extern void outsl (unsigned long port, const void *src, unsigned long count);
#define dma_cache_wback(_start,_size) do { flush_kernel_dcache_range(_start,_size); } while (0)
#define dma_cache_wback_inv(_start,_size) do { flush_kernel_dcache_range(_start,_size); } while (0)
/* PA machines have an MM I/O space from 0xf0000000-0xffffffff in 32
* bit mode and from 0xfffffffff0000000-0xfffffffffffffff in 64 bit
* mode (essentially just sign extending. This macro takes in a 32
* bit I/O address (still with the leading f) and outputs the correct
* value for either 32 or 64 bit mode */
#define F_EXTEND(x) ((unsigned long)((x) | (0xffffffff00000000ULL)))
#endif
#ifndef _ARCH_PARISC_LOCAL_H
#define _ARCH_PARISC_LOCAL_H
#include <linux/percpu.h>
#include <asm/atomic.h>
typedef atomic_t local_t;
#define LOCAL_INIT(i) ATOMIC_INIT(i)
#define local_read(v) atomic_read(v)
#define local_set(v,i) atomic_set(v,i)
#define local_inc(v) atomic_inc(v)
#define local_dec(v) atomic_dec(v)
#define local_add(i, v) atomic_add(i, v)
#define local_sub(i, v) atomic_sub(i, v)
#define __local_inc(v) ((v)->counter++)
#define __local_dec(v) ((v)->counter--)
#define __local_add(i,v) ((v)->counter+=(i))
#define __local_sub(i,v) ((v)->counter-=(i))
/* Use these for per-cpu local_t variables: on some archs they are
* much more efficient than these naive implementations. Note they take
* a variable, not an address.
*/
#define cpu_local_read(v) local_read(&__get_cpu_var(v))
#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i))
#define cpu_local_inc(v) local_inc(&__get_cpu_var(v))
#define cpu_local_dec(v) local_dec(&__get_cpu_var(v))
#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v))
#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v))
#define __cpu_local_inc(v) __local_inc(&__get_cpu_var(v))
#define __cpu_local_dec(v) __local_dec(&__get_cpu_var(v))
#define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v))
#define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v))
#endif /* _ARCH_PARISC_LOCAL_H */
#ifndef _PARISC_SECTIONS_H
#define _PARISC_SECTIONS_H
/* nothing to see, move along */
#include <asm-generic/sections.h>
#endif
......@@ -28,6 +28,11 @@
* that put_user is the same as __put_user, etc.
*/
extern int __get_kernel_bad(void);
extern int __get_user_bad(void);
extern int __put_kernel_bad(void);
extern int __put_user_bad(void);
#define access_ok(type,addr,size) (1)
#define verify_area(type,addr,size) (0)
......@@ -35,8 +40,8 @@
#define get_user __get_user
#if BITS_PER_LONG == 32
#define LDD_KERNEL(ptr) BUG()
#define LDD_USER(ptr) BUG()
#define LDD_KERNEL(ptr) __get_kernel_bad();
#define LDD_USER(ptr) __get_user_bad();
#define STD_KERNEL(x, ptr) __put_kernel_asm64((u32)x,ptr)
#define STD_USER(x, ptr) __put_user_asm64((u32)x,ptr)
#else
......@@ -72,7 +77,7 @@ struct exception_table_entry {
case 2: __get_kernel_asm("ldh",ptr); break; \
case 4: __get_kernel_asm("ldw",ptr); break; \
case 8: LDD_KERNEL(ptr); break; \
default: BUG(); break; \
default: __get_kernel_bad(); break; \
} \
} \
else { \
......@@ -81,7 +86,7 @@ struct exception_table_entry {
case 2: __get_user_asm("ldh",ptr); break; \
case 4: __get_user_asm("ldw",ptr); break; \
case 8: LDD_USER(ptr); break; \
default: BUG(); break; \
default: __get_user_bad(); break; \
} \
} \
\
......@@ -141,7 +146,7 @@ struct exception_table_entry {
case 2: __put_kernel_asm("sth",x,ptr); break; \
case 4: __put_kernel_asm("stw",x,ptr); break; \
case 8: STD_KERNEL(x,ptr); break; \
default: BUG(); break; \
default: __put_kernel_bad(); break; \
} \
} \
else { \
......@@ -150,7 +155,7 @@ struct exception_table_entry {
case 2: __put_user_asm("sth",x,ptr); break; \
case 4: __put_user_asm("stw",x,ptr); break; \
case 8: STD_USER(x,ptr); break; \
default: BUG(); break; \
default: __put_user_bad(); break; \
} \
} \
\
......
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