diff -urN linux-2.4.0-test4/Documentation/DMA-mapping.txt linux-2.4.0-test4-lia/Documentation/DMA-mapping.txt --- linux-2.4.0-test4/Documentation/DMA-mapping.txt Tue Apr 25 17:52:05 2000 +++ linux-2.4.0-test4-lia/Documentation/DMA-mapping.txt Fri Jul 28 22:51:03 2000 @@ -341,7 +341,7 @@ struct my_card_header *hp; /* Examine the header to see if we wish - * to except the data. But synchronize + * to accept the data. But synchronize * the DMA transfer with the CPU first * so that we see updated contents. */ diff -urN linux-2.4.0-test4/Makefile linux-2.4.0-test4-lia/Makefile --- linux-2.4.0-test4/Makefile Mon Jul 10 16:47:34 2000 +++ linux-2.4.0-test4-lia/Makefile Fri Jul 14 15:07:13 2000 @@ -82,7 +82,7 @@ CPPFLAGS := -D__KERNEL__ -I$(HPATH) -CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -g -O2 -fomit-frame-pointer AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) # diff -urN linux-2.4.0-test4/arch/ia64/Makefile linux-2.4.0-test4-lia/arch/ia64/Makefile --- linux-2.4.0-test4/arch/ia64/Makefile Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/Makefile Thu Jul 13 23:50:42 2000 @@ -11,6 +11,8 @@ NM := $(CROSS_COMPILE)nm -B AWK := awk +export AWK + LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds AFLAGS += -Wa,-x EXTRA = diff -urN linux-2.4.0-test4/arch/ia64/config.in linux-2.4.0-test4-lia/arch/ia64/config.in --- linux-2.4.0-test4/arch/ia64/config.in Wed Jul 12 15:12:11 2000 +++ linux-2.4.0-test4-lia/arch/ia64/config.in Fri Jul 28 22:53:08 2000 @@ -1,6 +1,3 @@ -# For a description of the syntax of this configuration file, -# see Documentation/kbuild/config-language.txt. -# mainmenu_name "Kernel configuration of Linux for IA-64 machines" mainmenu_option next_comment @@ -21,6 +18,7 @@ comment 'General setup' define_bool CONFIG_IA64 y +define_bool CONFIG_SWIOTLB y # for now... define_bool CONFIG_ISA n define_bool CONFIG_SBUS n @@ -42,6 +40,7 @@ define_bool CONFIG_IA64_BRL_EMU y bool ' Enable Itanium A-step specific code' CONFIG_ITANIUM_ASTEP_SPECIFIC bool ' Enable Itanium A1-step specific code' CONFIG_ITANIUM_A1_SPECIFIC + bool ' Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC bool ' Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG bool ' Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS bool ' Enable AzusA hacks' CONFIG_IA64_AZUSA_HACKS @@ -49,10 +48,6 @@ bool ' Enable IA64 Machine Check Abort' CONFIG_IA64_MCA fi -if [ "$CONFIG_IA64_GENERIC" = "y" ]; then - define_bool CONFIG_IA64_SOFTSDV_HACKS y -fi - if [ "$CONFIG_IA64_SGI_SN1_SIM" = "y" ]; then define_bool CONFIG_NUMA y define_bool CONFIG_IA64_SOFTSDV_HACKS y @@ -71,6 +66,8 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then + bool 'PCI support' CONFIG_PCI source drivers/pci/Config.in @@ -83,17 +80,21 @@ source drivers/parport/Config.in +fi # !HP_SIM + endmenu +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then + source drivers/mtd/Config.in source drivers/pnp/Config.in source drivers/block/Config.in source drivers/i2o/Config.in -if [ "$CONFIG_NET" = "y" ]; then - source net/Config.in -fi - mainmenu_option next_comment comment 'ATA/IDE/MFM/RLL support' @@ -107,6 +108,8 @@ fi endmenu +fi # !HP_SIM + mainmenu_option next_comment comment 'SCSI support' @@ -114,10 +117,11 @@ if [ "$CONFIG_SCSI" != "n" ]; then source drivers/scsi/Config.in - bool 'Simulated SCSI disk' CONFIG_SCSI_SIM fi endmenu +if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then + if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment comment 'Network device support' @@ -149,7 +153,10 @@ fi endmenu +fi # !HP_SIM + source drivers/char/Config.in + #source drivers/misc/Config.in source fs/Config.in @@ -167,6 +174,8 @@ endmenu fi +if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then + mainmenu_option next_comment comment 'Sound' @@ -177,6 +186,21 @@ endmenu source drivers/usb/Config.in + +fi # !HP_SIM + +if [ "$CONFIG_IA64_HP_SIM" != "n" -o "$CONFIG_IA64_GENERIC" != "n" ]; then + mainmenu_option next_comment + comment 'Simulated drivers' + + tristate 'Simulated Ethernet ' CONFIG_SIMETH + bool 'Simulated serial driver support' CONFIG_SIM_SERIAL + if [ "$CONFIG_SCSI" != "n" ]; then + bool 'Simulated SCSI disk' CONFIG_SCSI_SIM + fi + endmenu +fi + mainmenu_option next_comment comment 'Kernel hacking' diff -urN linux-2.4.0-test4/arch/ia64/dig/iosapic.c linux-2.4.0-test4-lia/arch/ia64/dig/iosapic.c --- linux-2.4.0-test4/arch/ia64/dig/iosapic.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/dig/iosapic.c Fri Jul 28 22:56:36 2000 @@ -22,12 +22,14 @@ #include #include +#include +#include #include #include +#include +#include #include #include -#include -#include #undef DEBUG_IRQ_ROUTING @@ -315,10 +317,6 @@ */ outb(0xff, 0xA1); outb(0xff, 0x21); - -#ifndef CONFIG_IA64_DIG - iosapic_init(IO_SAPIC_DEFAULT_ADDR); -#endif } void @@ -337,15 +335,23 @@ if (irq < 0 && dev->bus->parent) { /* go back to the bridge */ struct pci_dev * bridge = dev->bus->self; - /* do the bridge swizzle... */ - pin = (pin + PCI_SLOT(dev->devfn)) % 4; - irq = iosapic_get_PCI_irq_vector(bridge->bus->number, - PCI_SLOT(bridge->devfn), pin); + /* allow for multiple bridges on an adapter */ + do { + /* do the bridge swizzle... */ + pin = (pin + PCI_SLOT(dev->devfn)) % 4; + irq = iosapic_get_PCI_irq_vector(bridge->bus->number, + PCI_SLOT(bridge->devfn), pin); + } while (irq < 0 && (bridge = bridge->bus->self)); if (irq >= 0) printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %02x\n", bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq); + else + printk(KERN_WARNING + "PCI: Couldn't map irq for B%d,I%d,P%d\n", + bridge->bus->number, PCI_SLOT(bridge->devfn), + pin); } if (irq >= 0) { printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %02x\n", @@ -360,4 +366,35 @@ if (dev->irq >= NR_IRQS) dev->irq = 15; /* Spurious interrupts */ } +} + +/* + * Register an IOSAPIC discovered via ACPI. + */ +void __init +dig_register_iosapic (acpi_entry_iosapic_t *iosapic) +{ + unsigned int ver, v; + int l, max_pin; + + ver = iosapic_version(iosapic->address); + max_pin = (ver >> 16) & 0xff; + + printk("IOSAPIC Version %x.%x: address 0x%lx IRQs 0x%x - 0x%x\n", + (ver & 0xf0) >> 4, (ver & 0x0f), iosapic->address, + iosapic->irq_base, iosapic->irq_base + max_pin); + + for (l = 0; l <= max_pin; l++) { + v = iosapic->irq_base + l; + if (v < 16) + v = isa_irq_to_vector(v); + if (v > IA64_MAX_VECTORED_IRQ) { + printk(" !!! bad IOSAPIC interrupt vector: %u\n", v); + continue; + } + /* XXX Check for IOSAPIC collisions */ + iosapic_addr(v) = (unsigned long) ioremap(iosapic->address, 0); + iosapic_baseirq(v) = iosapic->irq_base; + } + iosapic_init(iosapic->address, iosapic->irq_base); } diff -urN linux-2.4.0-test4/arch/ia64/dig/machvec.c linux-2.4.0-test4-lia/arch/ia64/dig/machvec.c --- linux-2.4.0-test4/arch/ia64/dig/machvec.c Sun Feb 6 18:42:40 2000 +++ linux-2.4.0-test4-lia/arch/ia64/dig/machvec.c Fri Jul 28 22:56:47 2000 @@ -1,4 +1,2 @@ +#define MACHVEC_PLATFORM_NAME dig #include -#include - -MACHVEC_DEFINE(dig) diff -urN linux-2.4.0-test4/arch/ia64/dig/setup.c linux-2.4.0-test4-lia/arch/ia64/dig/setup.c --- linux-2.4.0-test4/arch/ia64/dig/setup.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/dig/setup.c Thu Jul 13 15:54:09 2000 @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff -urN linux-2.4.0-test4/arch/ia64/hp/hpsim_machvec.c linux-2.4.0-test4-lia/arch/ia64/hp/hpsim_machvec.c --- linux-2.4.0-test4/arch/ia64/hp/hpsim_machvec.c Sun Feb 6 18:42:40 2000 +++ linux-2.4.0-test4-lia/arch/ia64/hp/hpsim_machvec.c Fri Jul 28 22:56:57 2000 @@ -1,4 +1,2 @@ +#define MACHVEC_PLATFORM_NAME hpsim #include -#include - -MACHVEC_DEFINE(hpsim) diff -urN linux-2.4.0-test4/arch/ia64/hp/hpsim_setup.c linux-2.4.0-test4-lia/arch/ia64/hp/hpsim_setup.c --- linux-2.4.0-test4/arch/ia64/hp/hpsim_setup.c Sun Feb 6 18:42:40 2000 +++ linux-2.4.0-test4-lia/arch/ia64/hp/hpsim_setup.c Thu Jul 13 15:54:09 2000 @@ -63,6 +63,12 @@ } void __init +hpsim_pci_fixup (void) +{ +} + + +void __init hpsim_setup (char **cmdline_p) { ROOT_DEV = to_kdev_t(0x0801); /* default to first SCSI drive */ diff -urN linux-2.4.0-test4/arch/ia64/ia32/Makefile linux-2.4.0-test4-lia/arch/ia64/ia32/Makefile --- linux-2.4.0-test4/arch/ia64/ia32/Makefile Fri Apr 21 15:21:23 2000 +++ linux-2.4.0-test4-lia/arch/ia64/ia32/Makefile Thu Jul 13 15:54:09 2000 @@ -10,7 +10,7 @@ all: ia32.o O_TARGET := ia32.o -O_OBJS := ia32_entry.o sys_ia32.o ia32_signal.o ia32_support.o ia32_traps.o binfmt_elf32.o +O_OBJS := ia32_entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o ia32_support.o ia32_traps.o binfmt_elf32.o clean:: diff -urN linux-2.4.0-test4/arch/ia64/ia32/binfmt_elf32.c linux-2.4.0-test4-lia/arch/ia64/ia32/binfmt_elf32.c --- linux-2.4.0-test4/arch/ia64/ia32/binfmt_elf32.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/ia32/binfmt_elf32.c Thu Jul 13 15:54:09 2000 @@ -6,7 +6,8 @@ * 06/16/00 A. Mallick initialize csd/ssd/tssd/cflg for ia32_load_state */ #include -#include + +#include #include #include @@ -16,7 +17,9 @@ /* Override some function names */ #undef start_thread #define start_thread ia32_start_thread +#define elf_format elf32_format #define init_elf_binfmt init_elf32_binfmt +#define exit_elf_binfmt exit_elf32_binfmt #undef CONFIG_BINFMT_ELF #ifdef CONFIG_BINFMT_ELF32 @@ -28,10 +31,12 @@ # define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE #endif -void ia64_elf32_init(struct pt_regs *regs); -#define ELF_PLAT_INIT(_r) ia64_elf32_init(_r) +extern void ia64_elf32_init(struct pt_regs *regs); +extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address); +#define ELF_PLAT_INIT(_r) ia64_elf32_init(_r) #define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm) +#define elf_map elf_map32 /* Ugly but avoids duplication */ #include "../../../fs/binfmt_elf.c" @@ -200,4 +205,54 @@ } return 0; +} + +static unsigned long +ia32_mm_addr(unsigned long addr) +{ + struct vm_area_struct *vma; + + if ((vma = find_vma(current->mm, addr)) == NULL) + return(ELF_PAGESTART(addr)); + if (vma->vm_start > addr) + return(ELF_PAGESTART(addr)); + return(ELF_PAGEALIGN(addr)); +} + +/* + * Normally we would do an `mmap' to map in the process's text section. + * This doesn't work with IA32 processes as the ELF file might specify + * a non page size aligned address. Instead we will just allocate + * memory and read the data in from the file. Slightly less efficient + * but it works. + */ +extern long ia32_do_mmap (struct file *filep, unsigned int len, unsigned int prot, + unsigned int flags, unsigned int fd, unsigned int offset); + +static unsigned long +elf_map32 (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) +{ + unsigned long retval; + + if (eppnt->p_memsz >= (1UL<<32) || addr > (1UL<<32) - eppnt->p_memsz) + return -EINVAL; + +#if 1 + set_brk(ia32_mm_addr(addr), addr + eppnt->p_memsz); + memset((char *) addr + eppnt->p_filesz, 0, eppnt->p_memsz - eppnt->p_filesz); + kernel_read(filep, eppnt->p_offset, (char *) addr, eppnt->p_filesz); + retval = (unsigned long) addr; +#else + /* doesn't work yet... */ +# define IA32_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1)) +# define IA32_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1)) +# define IA32_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1)) + + down(¤t->mm->mmap_sem); + retval = ia32_do_mmap(filep, IA32_PAGESTART(addr), + eppnt->p_filesz + IA32_PAGEOFFSET(eppnt->p_vaddr), prot, type, + eppnt->p_offset - IA32_PAGEOFFSET(eppnt->p_vaddr)); + up(¤t->mm->mmap_sem); +#endif + return retval; } diff -urN linux-2.4.0-test4/arch/ia64/ia32/ia32_entry.S linux-2.4.0-test4-lia/arch/ia64/ia32/ia32_entry.S --- linux-2.4.0-test4/arch/ia64/ia32/ia32_entry.S Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/ia32/ia32_entry.S Fri Jul 28 22:57:12 2000 @@ -63,13 +63,13 @@ GLOBAL_ENTRY(ia32_trace_syscall) PT_REGS_UNWIND_INFO(0) br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args -.Lret4: br.call.sptk.few rp=b6 // do the syscall -.Lret5: cmp.lt p6,p0=r8,r0 // syscall failed? +.ret0: br.call.sptk.few rp=b6 // do the syscall +.ret1: cmp.lt p6,p0=r8,r0 // syscall failed? adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 ;; st8.spill [r2]=r8 // store return value in slot for r8 br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value -.Lret6: br.cond.sptk.many ia64_leave_kernel // rp MUST be != ia64_leave_kernel! +.ret2: br.cond.sptk.many ia64_leave_kernel // rp MUST be != ia64_leave_kernel! END(ia32_trace_syscall) GLOBAL_ENTRY(sys32_vfork) @@ -80,7 +80,7 @@ GLOBAL_ENTRY(sys32_fork) UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) - alloc r16=ar.pfs,2,2,3,0 + alloc r16=ar.pfs,2,2,4,0 mov out0=SIGCHLD // out0 = clone_flags ;; .fork1: @@ -90,13 +90,11 @@ UNW(.body) - adds out2=IA64_SWITCH_STACK_SIZE+16,sp - adds r2=IA64_SWITCH_STACK_SIZE+IA64_PT_REGS_R12_OFFSET+16,sp - ;; - ld8 out1=[r2] // fetch usp from pt_regs.r12 + mov out1=0 + mov out2=0 + adds out3=IA64_SWITCH_STACK_SIZE+16,sp br.call.sptk.few rp=do_fork -.ret1: - mov ar.pfs=loc1 +.ret3: mov ar.pfs=loc1 UNW(.restore sp) adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov rp=loc0 @@ -107,7 +105,7 @@ .align 8 .globl ia32_syscall_table ia32_syscall_table: - data8 sys_ni_syscall /* 0 - old "setup(" system call*/ + data8 sys32_ni_syscall /* 0 - old "setup(" system call*/ data8 sys_exit data8 sys32_fork data8 sys_read @@ -124,25 +122,25 @@ data8 sys_mknod data8 sys_chmod /* 15 */ data8 sys_lchown - data8 sys_ni_syscall /* old break syscall holder */ - data8 sys_ni_syscall + data8 sys32_ni_syscall /* old break syscall holder */ + data8 sys32_ni_syscall data8 sys_lseek data8 sys_getpid /* 20 */ data8 sys_mount data8 sys_oldumount data8 sys_setuid data8 sys_getuid - data8 sys_ni_syscall /* sys_stime is not supported on IA64 */ /* 25 */ + data8 sys32_ni_syscall /* sys_stime is not supported on IA64 */ /* 25 */ data8 sys32_ptrace data8 sys32_alarm - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 30 */ - data8 sys_ni_syscall /* old stty syscall holder */ - data8 sys_ni_syscall /* old gtty syscall holder */ + data8 sys32_ni_syscall + data8 sys32_ni_syscall + data8 ia32_utime /* 30 */ + data8 sys32_ni_syscall /* old stty syscall holder */ + data8 sys32_ni_syscall /* old gtty syscall holder */ data8 sys_access data8 sys_nice - data8 sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + data8 sys32_ni_syscall /* 35 */ /* old ftime syscall holder */ data8 sys_sync data8 sys_kill data8 sys_rename @@ -151,22 +149,22 @@ data8 sys_dup data8 sys32_pipe data8 sys32_times - data8 sys_ni_syscall /* old prof syscall holder */ + data8 sys32_ni_syscall /* old prof syscall holder */ data8 sys_brk /* 45 */ data8 sys_setgid data8 sys_getgid - data8 sys_ni_syscall + data8 sys32_ni_syscall data8 sys_geteuid data8 sys_getegid /* 50 */ data8 sys_acct data8 sys_umount /* recycled never used phys( */ - data8 sys_ni_syscall /* old lock syscall holder */ - data8 sys_ioctl - data8 sys_fcntl /* 55 */ - data8 sys_ni_syscall /* old mpx syscall holder */ + data8 sys32_ni_syscall /* old lock syscall holder */ + data8 ia32_ioctl + data8 sys32_fcntl /* 55 */ + data8 sys32_ni_syscall /* old mpx syscall holder */ data8 sys_setpgid - data8 sys_ni_syscall /* old ulimit syscall holder */ - data8 sys_ni_syscall + data8 sys32_ni_syscall /* old ulimit syscall holder */ + data8 sys32_ni_syscall data8 sys_umask /* 60 */ data8 sys_chroot data8 sys_ustat @@ -174,12 +172,12 @@ data8 sys_getppid data8 sys_getpgrp /* 65 */ data8 sys_setsid - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall + data8 sys32_sigaction + data8 sys32_ni_syscall + data8 sys32_ni_syscall data8 sys_setreuid /* 70 */ data8 sys_setregid - data8 sys_ni_syscall + data8 sys32_ni_syscall data8 sys_sigpending data8 sys_sethostname data8 sys32_setrlimit /* 75 */ @@ -191,7 +189,7 @@ data8 sys_setgroups data8 old_select data8 sys_symlink - data8 sys_ni_syscall + data8 sys32_ni_syscall data8 sys_readlink /* 85 */ data8 sys_uselib data8 sys_swapon @@ -205,7 +203,7 @@ data8 sys_fchown /* 95 */ data8 sys_getpriority data8 sys_setpriority - data8 sys_ni_syscall /* old profil syscall holder */ + data8 sys32_ni_syscall /* old profil syscall holder */ data8 sys32_statfs data8 sys32_fstatfs /* 100 */ data8 sys_ioperm @@ -216,11 +214,11 @@ data8 sys32_newstat data8 sys32_newlstat data8 sys32_newfstat - data8 sys_ni_syscall + data8 sys32_ni_syscall data8 sys_iopl /* 110 */ data8 sys_vhangup - data8 sys_ni_syscall // used to be sys_idle - data8 sys_ni_syscall + data8 sys32_ni_syscall // used to be sys_idle + data8 sys32_ni_syscall data8 sys32_wait4 data8 sys_swapoff /* 115 */ data8 sys_sysinfo @@ -244,7 +242,7 @@ data8 sys_bdflush data8 sys_sysfs /* 135 */ data8 sys_personality - data8 sys_ni_syscall /* for afs_syscall */ + data8 sys32_ni_syscall /* for afs_syscall */ data8 sys_setfsuid data8 sys_setfsgid data8 sys_llseek /* 140 */ @@ -295,8 +293,8 @@ data8 sys_capset /* 185 */ data8 sys_sigaltstack data8 sys_sendfile - data8 sys_ni_syscall /* streams1 */ - data8 sys_ni_syscall /* streams2 */ + data8 sys32_ni_syscall /* streams1 */ + data8 sys32_ni_syscall /* streams2 */ data8 sys32_vfork /* 190 */ /* * CAUTION: If any system calls are added beyond this point diff -urN linux-2.4.0-test4/arch/ia64/ia32/ia32_ioctl.c linux-2.4.0-test4-lia/arch/ia64/ia32/ia32_ioctl.c --- linux-2.4.0-test4/arch/ia64/ia32/ia32_ioctl.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.0-test4-lia/arch/ia64/ia32/ia32_ioctl.c Thu Jul 13 15:54:09 2000 @@ -0,0 +1,102 @@ +/* + * IA32 Architecture-specific ioctl shim code + * + * Copyright (C) 2000 VA Linux Co + * Copyright (C) 2000 Don Dugger + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); + +asmlinkage long ia32_ioctl(unsigned int fd, unsigned int cmd, unsigned int arg) +{ + + switch (cmd) { + + case VFAT_IOCTL_READDIR_BOTH: + case VFAT_IOCTL_READDIR_SHORT: + case MTIOCGET: + case MTIOCPOS: + case MTIOCGETCONFIG: + case MTIOCSETCONFIG: + case PPPIOCSCOMPRESS: + case PPPIOCGIDLE: + case NCP_IOC_GET_FS_INFO_V2: + case NCP_IOC_GETOBJECTNAME: + case NCP_IOC_SETOBJECTNAME: + case NCP_IOC_GETPRIVATEDATA: + case NCP_IOC_SETPRIVATEDATA: + case NCP_IOC_GETMOUNTUID2: + case CAPI_MANUFACTURER_CMD: + case VIDIOCGTUNER: + case VIDIOCSTUNER: + case VIDIOCGWIN: + case VIDIOCSWIN: + case VIDIOCGFBUF: + case VIDIOCSFBUF: + case MGSL_IOCSPARAMS: + case MGSL_IOCGPARAMS: + case ATM_GETNAMES: + case ATM_GETLINKRATE: + case ATM_GETTYPE: + case ATM_GETESI: + case ATM_GETADDR: + case ATM_RSTADDR: + case ATM_ADDADDR: + case ATM_DELADDR: + case ATM_GETCIRANGE: + case ATM_SETCIRANGE: + case ATM_SETESI: + case ATM_SETESIF: + case ATM_GETSTAT: + case ATM_GETSTATZ: + case ATM_GETLOOP: + case ATM_SETLOOP: + case ATM_QUERYLOOP: + case ENI_SETMULT: + case NS_GETPSTAT: + /* case NS_SETBUFLEV: This is a duplicate case with ZATM_GETPOOLZ */ + case ZATM_GETPOOLZ: + case ZATM_GETPOOL: + case ZATM_SETPOOL: + case ZATM_GETTHIST: + case IDT77105_GETSTAT: + case IDT77105_GETSTATZ: + case IXJCTL_TONE_CADENCE: + case IXJCTL_FRAMES_READ: + case IXJCTL_FRAMES_WRITTEN: + case IXJCTL_READ_WAIT: + case IXJCTL_WRITE_WAIT: + case IXJCTL_DRYBUFFER_READ: + case I2OHRTGET: + case I2OLCTGET: + case I2OPARMSET: + case I2OPARMGET: + case I2OSWDL: + case I2OSWUL: + case I2OSWDEL: + case I2OHTML: + printk("%x:unimplemented IA32 ioctl system call\n", cmd); + return(-EINVAL); + default: + return(sys_ioctl(fd, cmd, (unsigned long)arg)); + + } +} diff -urN linux-2.4.0-test4/arch/ia64/ia32/sys_ia32.c linux-2.4.0-test4-lia/arch/ia64/ia32/sys_ia32.c --- linux-2.4.0-test4/arch/ia64/ia32/sys_ia32.c Sat Jul 8 19:26:11 2000 +++ linux-2.4.0-test4-lia/arch/ia64/ia32/sys_ia32.c Fri Jul 28 22:57:21 2000 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -73,10 +74,14 @@ n = 0; do { - if ((err = get_user(addr, (int *)A(arg))) != 0) - return(err); - if (ap) - *ap++ = (char *)A(addr); + err = get_user(addr, (int *)A(arg)); + if (IS_ERR(err)) + return err; + if (ap) { /* no access_ok needed, we allocated */ + err = __put_user((char *)A(addr), ap++); + if (IS_ERR(err)) + return err; + } arg += sizeof(unsigned int); n++; } while (addr); @@ -100,7 +105,11 @@ int na, ne, r, len; na = nargs(argv, NULL); + if (IS_ERR(na)) + return(na); ne = nargs(envp, NULL); + if (IS_ERR(ne)) + return(ne); len = (na + ne + 2) * sizeof(*av); /* * kmalloc won't work because the `sys_exec' code will attempt @@ -120,12 +129,21 @@ if (IS_ERR(av)) return (long)av; ae = av + na + 1; - av[na] = (char *)0; - ae[ne] = (char *)0; - (void)nargs(argv, av); - (void)nargs(envp, ae); + r = __put_user(0, (av + na)); + if (IS_ERR(r)) + goto out; + r = __put_user(0, (ae + ne)); + if (IS_ERR(r)) + goto out; + r = nargs(argv, av); + if (IS_ERR(r)) + goto out; + r = nargs(envp, ae); + if (IS_ERR(r)) + goto out; r = sys_execve(filename, av, ae, regs); if (IS_ERR(r)) +out: sys_munmap((unsigned long) av, len); return(r); } @@ -207,7 +225,7 @@ unsigned long do_mmap_fake(struct file *file, unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, unsigned long off) + unsigned long prot, unsigned long flags, loff_t off) { struct inode *inode; void *front, *back; @@ -224,11 +242,11 @@ back = NULL; if ((baddr = (addr & PAGE_MASK)) != addr && get_user(c, (char *)baddr) == 0) { front = kmalloc(addr - baddr, GFP_KERNEL); - memcpy(front, (void *)baddr, addr - baddr); + __copy_user(front, (void *)baddr, addr - baddr); } if (addr && ((addr + len) & ~PAGE_MASK) && get_user(c, (char *)(addr + len)) == 0) { back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL); - memcpy(back, (char *)addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); + __copy_user(back, (char *)addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); } down(¤t->mm->mmap_sem); r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0); @@ -238,15 +256,15 @@ if (addr == 0) addr = r; if (back) { - memcpy((char *)addr + len, back, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); + __copy_user((char *)addr + len, back, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); kfree(back); } if (front) { - memcpy((void *)baddr, front, addr - baddr); + __copy_user((void *)baddr, front, addr - baddr); kfree(front); } if (flags & MAP_ANONYMOUS) { - memset((char *)addr, 0, len); + clear_user((char *)addr, len); return(addr); } if (!file) @@ -256,19 +274,39 @@ return -EINVAL; if (!file->f_op->read) return -EINVAL; - lock_kernel(); - if (file->f_op->llseek) { - if (file->f_op->llseek(file,off,0) != off) { - unlock_kernel(); - return -EINVAL; - } - } else - file->f_pos = off; - unlock_kernel(); - r = file->f_op->read(file, (char *)addr, len, &file->f_pos); + r = file->f_op->read(file, (char *)addr, len, &off); return (r < 0) ? -EINVAL : addr; } +long +ia32_do_mmap (struct file *file, unsigned int addr, unsigned int len, unsigned int prot, + unsigned int flags, unsigned int fd, unsigned int offset) +{ + long error = -EFAULT; + unsigned int poff; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK))) + error = do_mmap_fake(file, addr, len, prot, flags, (loff_t)offset); + else if (!addr && (offset & ~PAGE_MASK)) { + poff = offset & PAGE_MASK; + len += offset - poff; + + down(¤t->mm->mmap_sem); + error = do_mmap(file, addr, len, prot, flags, poff); + up(¤t->mm->mmap_sem); + + if (!IS_ERR(error)) + error += offset - poff; + } else { + down(¤t->mm->mmap_sem); + error = do_mmap(file, addr, len, prot, flags, offset); + up(¤t->mm->mmap_sem); + } + return error; +} + /* * Linux/i386 didn't use to be able to handle more than * 4 system call parameters, so these system calls used a memory @@ -287,32 +325,22 @@ asmlinkage long sys32_mmap(struct mmap_arg_struct *arg) { - int error = -EFAULT; - struct file * file = NULL; struct mmap_arg_struct a; + struct file *file = NULL; + long retval; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; if (!(a.flags & MAP_ANONYMOUS)) { - error = -EBADF; file = fget(a.fd); if (!file) - goto out; - } - a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - if ((a.flags & MAP_FIXED) && ((a.addr & ~PAGE_MASK) || (a.offset & ~PAGE_MASK))) { - error = do_mmap_fake(file, a.addr, a.len, a.prot, a.flags, a.offset); - } else { - down(¤t->mm->mmap_sem); - error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); - up(¤t->mm->mmap_sem); + return -EBADF; } + retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset); if (file) fput(file); -out: - return error; + return retval; } asmlinkage long @@ -602,6 +630,40 @@ /* Translations due to time_t size differences. Which affects all sorts of things, like timeval and itimerval. */ +struct utimbuf_32 { + int atime; + int mtime; +}; + +extern asmlinkage long sys_utimes(char * filename, struct timeval * utimes); +extern asmlinkage long sys_gettimeofday (struct timeval *tv, struct timezone *tz); + +asmlinkage long +ia32_utime(char * filename, struct utimbuf_32 *times32) +{ + mm_segment_t old_fs = get_fs(); + struct timeval tv[2]; + long ret; + + if (times32) { + get_user(tv[0].tv_sec, ×32->atime); + tv[0].tv_usec = 0; + get_user(tv[1].tv_sec, ×32->mtime); + tv[1].tv_usec = 0; + set_fs (KERNEL_DS); + } else { + set_fs (KERNEL_DS); + ret = sys_gettimeofday(&tv[0], 0); + if (ret < 0) + goto out; + tv[1] = tv[0]; + } + ret = sys_utimes(filename, tv); + out: + set_fs (old_fs); + return ret; +} + extern struct timezone sys_tz; extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz); @@ -914,150 +976,85 @@ } struct iovec32 { unsigned int iov_base; int iov_len; }; +asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long); +asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long); -typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *); - -static long -do_readv_writev32(int type, struct file *file, const struct iovec32 *vector, - u32 count) +static struct iovec * +get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type) { - unsigned long tot_len; - struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov=iovstack, *ivp; - struct inode *inode; - long retval, i; - IO_fn_t fn; + int i; + u32 buf, len; + struct iovec *ivp, *iov; + + /* Get the "struct iovec" from user memory */ - /* First get the "struct iovec" from user memory and - * verify all the pointers - */ if (!count) return 0; - if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count)) - return -EFAULT; + if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count)) + return(struct iovec *)0; if (count > UIO_MAXIOV) - return -EINVAL; + return(struct iovec *)0; if (count > UIO_FASTIOV) { iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); if (!iov) - return -ENOMEM; - } + return((struct iovec *)0); + } else + iov = iov_buf; - tot_len = 0; - i = count; ivp = iov; - while(i > 0) { - u32 len; - u32 buf; - - __get_user(len, &vector->iov_len); - __get_user(buf, &vector->iov_base); - tot_len += len; + for (i = 0; i < count; i++) { + if (__get_user(len, &iov32->iov_len) || + __get_user(buf, &iov32->iov_base)) { + if (iov != iov_buf) + kfree(iov); + return((struct iovec *)0); + } + if (verify_area(type, (void *)A(buf), len)) { + if (iov != iov_buf) + kfree(iov); + return((struct iovec *)0); + } ivp->iov_base = (void *)A(buf); - ivp->iov_len = (__kernel_size_t) len; - vector++; - ivp++; - i--; - } - - inode = file->f_dentry->d_inode; - /* VERIFY_WRITE actually means a read, as we write to user space */ - retval = locks_verify_area((type == VERIFY_WRITE - ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE), - inode, file, file->f_pos, tot_len); - if (retval) { - if (iov != iovstack) - kfree(iov); - return retval; - } - - /* Then do the actual IO. Note that sockets need to be handled - * specially as they have atomicity guarantees and can handle - * iovec's natively - */ - if (inode->i_sock) { - int err; - err = sock_readv_writev(type, inode, file, iov, count, tot_len); - if (iov != iovstack) - kfree(iov); - return err; - } - - if (!file->f_op) { - if (iov != iovstack) - kfree(iov); - return -EINVAL; - } - /* VERIFY_WRITE actually means a read, as we write to user space */ - fn = file->f_op->read; - if (type == VERIFY_READ) - fn = (IO_fn_t) file->f_op->write; - ivp = iov; - while (count > 0) { - void * base; - int len, nr; - - base = ivp->iov_base; - len = ivp->iov_len; + ivp->iov_len = (__kernel_size_t)len; + iov32++; ivp++; - count--; - nr = fn(file, base, len, &file->f_pos); - if (nr < 0) { - if (retval) - break; - retval = nr; - break; - } - retval += nr; - if (nr != len) - break; } - if (iov != iovstack) - kfree(iov); - return retval; + return(iov); } asmlinkage long sys32_readv(int fd, struct iovec32 *vector, u32 count) { - struct file *file; - long ret = -EBADF; - - file = fget(fd); - if(!file) - goto bad_file; - - if(!(file->f_mode & 1)) - goto out; + struct iovec iovstack[UIO_FASTIOV]; + struct iovec *iov; + int ret; + mm_segment_t old_fs = get_fs(); - ret = do_readv_writev32(VERIFY_WRITE, file, - vector, count); -out: - fput(file); -bad_file: + if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE)) == (struct iovec *)0) + return -EFAULT; + set_fs(KERNEL_DS); + ret = sys_readv(fd, iov, count); + set_fs(old_fs); + if (iov != iovstack) + kfree(iov); return ret; } asmlinkage long sys32_writev(int fd, struct iovec32 *vector, u32 count) { - struct file *file; - int ret = -EBADF; - - file = fget(fd); - if(!file) - goto bad_file; - - if(!(file->f_mode & 2)) - goto out; + struct iovec iovstack[UIO_FASTIOV]; + struct iovec *iov; + int ret; + mm_segment_t old_fs = get_fs(); - down(&file->f_dentry->d_inode->i_sem); - ret = do_readv_writev32(VERIFY_READ, file, - vector, count); - up(&file->f_dentry->d_inode->i_sem); -out: - fput(file); -bad_file: + if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ)) == (struct iovec *)0) + return -EFAULT; + set_fs(KERNEL_DS); + ret = sys_writev(fd, iov, count); + set_fs(old_fs); + if (iov != iovstack) + kfree(iov); return ret; } @@ -1128,21 +1125,22 @@ static inline int shape_msg(struct msghdr *mp, struct msghdr32 *mp32) { + int ret; unsigned int i; if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32))) return(-EFAULT); - __get_user(i, &mp32->msg_name); + ret = __get_user(i, &mp32->msg_name); mp->msg_name = (void *)A(i); - __get_user(mp->msg_namelen, &mp32->msg_namelen); - __get_user(i, &mp32->msg_iov); + ret |= __get_user(mp->msg_namelen, &mp32->msg_namelen); + ret |= __get_user(i, &mp32->msg_iov); mp->msg_iov = (struct iovec *)A(i); - __get_user(mp->msg_iovlen, &mp32->msg_iovlen); - __get_user(i, &mp32->msg_control); + ret |= __get_user(mp->msg_iovlen, &mp32->msg_iovlen); + ret |= __get_user(i, &mp32->msg_control); mp->msg_control = (void *)A(i); - __get_user(mp->msg_controllen, &mp32->msg_controllen); - __get_user(mp->msg_flags, &mp32->msg_flags); - return(0); + ret |= __get_user(mp->msg_controllen, &mp32->msg_controllen); + ret |= __get_user(mp->msg_flags, &mp32->msg_flags); + return(ret ? -EFAULT : 0); } /* @@ -2296,17 +2294,17 @@ { struct switch_stack *swp; struct pt_regs *ptp; - int i, tos; + int i, tos, ret; int fsrlo, fsrhi; if (!access_ok(VERIFY_READ, save, sizeof(*save))) return(-EIO); - __get_user(tsk->thread.fcr, (unsigned int *)&save->cw); - __get_user(fsrlo, (unsigned int *)&save->sw); - __get_user(fsrhi, (unsigned int *)&save->tag); + ret = __get_user(tsk->thread.fcr, (unsigned int *)&save->cw); + ret |= __get_user(fsrlo, (unsigned int *)&save->sw); + ret |= __get_user(fsrhi, (unsigned int *)&save->tag); tsk->thread.fsr = ((long)fsrhi << 32) | (long)fsrlo; - __get_user(tsk->thread.fir, (unsigned int *)&save->ipoff); - __get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff); + ret |= __get_user(tsk->thread.fir, (unsigned int *)&save->ipoff); + ret |= __get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff); /* * Stack frames start with 16-bytes of temp space */ @@ -2315,7 +2313,7 @@ tos = (tsk->thread.fsr >> 11) & 3; for (i = 0; i < 8; i++) get_fpreg(i, &save->_st[i], ptp, swp, tos); - return(0); + return(ret ? -EFAULT : 0); } asmlinkage long sys_ptrace(long, pid_t, unsigned long, unsigned long, long, long, long, long, long); @@ -2359,7 +2357,7 @@ goto out; } ret = -ESRCH; - if (!(child->flags & PF_PTRACED)) + if (!(child->ptrace & PT_PTRACED)) goto out; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) @@ -2447,6 +2445,105 @@ return ret; } +static inline int +get_flock32(struct flock *kfl, struct flock32 *ufl) +{ + int err; + + err = get_user(kfl->l_type, &ufl->l_type); + err |= __get_user(kfl->l_whence, &ufl->l_whence); + err |= __get_user(kfl->l_start, &ufl->l_start); + err |= __get_user(kfl->l_len, &ufl->l_len); + err |= __get_user(kfl->l_pid, &ufl->l_pid); + return err; +} + +static inline int +put_flock32(struct flock *kfl, struct flock32 *ufl) +{ + int err; + + err = __put_user(kfl->l_type, &ufl->l_type); + err |= __put_user(kfl->l_whence, &ufl->l_whence); + err |= __put_user(kfl->l_start, &ufl->l_start); + err |= __put_user(kfl->l_len, &ufl->l_len); + err |= __put_user(kfl->l_pid, &ufl->l_pid); + return err; +} + +extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, + unsigned long arg); + +asmlinkage long +sys32_fcntl(unsigned int fd, unsigned int cmd, int arg) +{ + struct flock f; + mm_segment_t old_fs; + long ret; + + switch (cmd) { + case F_GETLK: + case F_SETLK: + case F_SETLKW: + if(cmd != F_GETLK && get_flock32(&f, (struct flock32 *)((long)arg))) + return -EFAULT; + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_fcntl(fd, cmd, (unsigned long)&f); + set_fs(old_fs); + if(cmd == F_GETLK && put_flock32(&f, (struct flock32 *)((long)arg))) + return -EFAULT; + return ret; + default: + /* + * `sys_fcntl' lies about arg, for the F_SETOWN + * sub-function arg can have a negative value. + */ + return sys_fcntl(fd, cmd, (unsigned long)((long)arg)); + } +} + +asmlinkage long +sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset32_t mask; + + ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); + ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + ret |= __get_user(mask, &act->sa_mask); + if (ret) + return ret; + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); + ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +asmlinkage long sys_ni_syscall(void); + +asmlinkage long +sys32_ni_syscall(int dummy0, int dummy1, int dummy2, int dummy3, + int dummy4, int dummy5, int dummy6, int dummy7, int stack) +{ + struct pt_regs *regs = (struct pt_regs *)&stack; + + printk("IA32 syscall #%d issued, maybe we should implement it\n", + (int)regs->r1); + return(sys_ni_syscall()); +} + #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ /* In order to reduce some races, while at the same time doing additional @@ -2500,61 +2597,6 @@ return sys_ioperm((unsigned long)from, (unsigned long)num, on); } -static inline int -get_flock(struct flock *kfl, struct flock32 *ufl) -{ - int err; - - err = get_user(kfl->l_type, &ufl->l_type); - err |= __get_user(kfl->l_whence, &ufl->l_whence); - err |= __get_user(kfl->l_start, &ufl->l_start); - err |= __get_user(kfl->l_len, &ufl->l_len); - err |= __get_user(kfl->l_pid, &ufl->l_pid); - return err; -} - -static inline int -put_flock(struct flock *kfl, struct flock32 *ufl) -{ - int err; - - err = __put_user(kfl->l_type, &ufl->l_type); - err |= __put_user(kfl->l_whence, &ufl->l_whence); - err |= __put_user(kfl->l_start, &ufl->l_start); - err |= __put_user(kfl->l_len, &ufl->l_len); - err |= __put_user(kfl->l_pid, &ufl->l_pid); - return err; -} - -extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, - unsigned long arg); - -asmlinkage long -sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case F_GETLK: - case F_SETLK: - case F_SETLKW: - { - struct flock f; - mm_segment_t old_fs; - long ret; - - if(get_flock(&f, (struct flock32 *)arg)) - return -EFAULT; - old_fs = get_fs(); set_fs (KERNEL_DS); - ret = sys_fcntl(fd, cmd, (unsigned long)&f); - set_fs (old_fs); - if(put_flock(&f, (struct flock32 *)arg)) - return -EFAULT; - return ret; - } - default: - return sys_fcntl(fd, cmd, (unsigned long)arg); - } -} - struct dqblk32 { __u32 dqb_bhardlimit; __u32 dqb_bsoftlimit; @@ -3816,40 +3858,6 @@ } extern void check_pending(int signum); - -asmlinkage long -sys32_sigaction (int sig, struct old_sigaction32 *act, - struct old_sigaction32 *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if(sig < 0) { - current->tss.new_signal = 1; - sig = -sig; - } - - if (act) { - old_sigset_t32 mask; - - ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); - ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); - ret |= __get_user(mask, &act->sa_mask); - if (ret) - return ret; - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); - ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } - - return ret; -} #ifdef CONFIG_MODULES diff -urN linux-2.4.0-test4/arch/ia64/kernel/Makefile linux-2.4.0-test4-lia/arch/ia64/kernel/Makefile --- linux-2.4.0-test4/arch/ia64/kernel/Makefile Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/Makefile Fri Jul 28 22:58:05 2000 @@ -9,35 +9,20 @@ all: kernel.o head.o init_task.o +obj-y := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o \ + machvec.o pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \ + signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o + +obj-$(CONFIG_IA64_GENERIC) += machvec.o +obj-$(CONFIG_IA64_PALINFO) += palinfo.o +obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_IA64_MCA) += mca.o mca_asm.o +obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o + O_TARGET := kernel.o -O_OBJS := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o \ - pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \ - signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o +O_OBJS := $(obj-y) OX_OBJS := ia64_ksyms.o - -ifdef CONFIG_IA64_GENERIC -O_OBJS += machvec.o -endif - -ifdef CONFIG_IA64_PALINFO -O_OBJS += palinfo.o -endif - -ifdef CONFIG_PCI -O_OBJS += pci.o -endif - -ifdef CONFIG_SMP -O_OBJS += smp.o -endif - -ifdef CONFIG_IA64_MCA -O_OBJS += mca.o mca_asm.o -endif - -ifdef CONFIG_IA64_BRL_EMU -O_OBJS += brl_emu.o -endif clean:: diff -urN linux-2.4.0-test4/arch/ia64/kernel/acpi.c linux-2.4.0-test4-lia/arch/ia64/kernel/acpi.c --- linux-2.4.0-test4/arch/ia64/kernel/acpi.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/acpi.c Fri Jul 28 22:58:16 2000 @@ -19,10 +19,11 @@ #include #include -#include #include #include #include +#include +#include #undef ACPI_DEBUG /* Guess what this does? */ @@ -75,47 +76,6 @@ } /* - * Find all IOSAPICs and tag the iosapic_vector structure with the appropriate - * base addresses. - */ -static void __init -acpi_iosapic(char *p) -{ - /* - * This is not good. ACPI is not necessarily limited to CONFIG_IA64_SV, yet - * ACPI does not necessarily imply IOSAPIC either. Perhaps there should be - * a means for platform_setup() to register ACPI handlers? - */ -#ifdef CONFIG_IA64_DIG - acpi_entry_iosapic_t *iosapic = (acpi_entry_iosapic_t *) p; - unsigned int ver, v; - int l, max_pin; - - ver = iosapic_version(iosapic->address); - max_pin = (ver >> 16) & 0xff; - - printk("IOSAPIC Version %x.%x: address 0x%lx IRQs 0x%x - 0x%x\n", - (ver & 0xf0) >> 4, (ver & 0x0f), iosapic->address, - iosapic->irq_base, iosapic->irq_base + max_pin); - - for (l = 0; l <= max_pin; l++) { - v = iosapic->irq_base + l; - if (v < 16) - v = isa_irq_to_vector(v); - if (v > IA64_MAX_VECTORED_IRQ) { - printk(" !!! bad IOSAPIC interrupt vector: %u\n", v); - continue; - } - /* XXX Check for IOSAPIC collisions */ - iosapic_addr(v) = (unsigned long) ioremap(iosapic->address, 0); - iosapic_baseirq(v) = iosapic->irq_base; - } - iosapic_init(iosapic->address, iosapic->irq_base); -#endif -} - - -/* * Configure legacy IRQ information in iosapic_vector */ static void __init @@ -227,7 +187,7 @@ break; case ACPI_ENTRY_IO_SAPIC: - acpi_iosapic(p); + platform_register_iosapic((acpi_entry_iosapic_t *) p); break; case ACPI_ENTRY_INT_SRC_OVERRIDE: diff -urN linux-2.4.0-test4/arch/ia64/kernel/efi.c linux-2.4.0-test4-lia/arch/ia64/kernel/efi.c --- linux-2.4.0-test4/arch/ia64/kernel/efi.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/efi.c Fri Jul 28 22:58:24 2000 @@ -33,9 +33,10 @@ extern efi_status_t efi_call_phys (void *, ...); struct efi efi; - static efi_runtime_services_t *runtime; +static unsigned long mem_limit = ~0UL; + static efi_status_t phys_get_time (efi_time_t *tm, efi_time_cap_t *tc) { @@ -169,15 +170,13 @@ case EFI_BOOT_SERVICES_CODE: case EFI_BOOT_SERVICES_DATA: case EFI_CONVENTIONAL_MEMORY: - if (md->phys_addr > 1024*1024*1024UL) { - printk("Warning: ignoring %luMB of memory above 1GB!\n", - md->num_pages >> 8); - md->type = EFI_UNUSABLE_MEMORY; - continue; - } - if (!(md->attribute & EFI_MEMORY_WB)) continue; + if (md->phys_addr + (md->num_pages << 12) > mem_limit) { + if (md->phys_addr > mem_limit) + continue; + md->num_pages = (mem_limit - md->phys_addr) >> 12; + } if (md->num_pages == 0) { printk("efi_memmap_walk: ignoring empty region at 0x%lx", md->phys_addr); @@ -224,8 +223,8 @@ * ITR to enable safe PAL calls in virtual mode. See IA-64 Processor * Abstraction Layer chapter 11 in ADAG */ -static void -map_pal_code (void) +void +efi_map_pal_code (void) { void *efi_map_start, *efi_map_end, *p; efi_memory_desc_t *md; @@ -240,7 +239,8 @@ for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; - if (md->type != EFI_PAL_CODE) continue; + if (md->type != EFI_PAL_CODE) + continue; if (++pal_code_count > 1) { printk(KERN_ERR "Too many EFI Pal Code memory ranges, dropped @ %lx\n", @@ -281,9 +281,28 @@ efi_config_table_t *config_tables; efi_char16_t *c16; u64 efi_desc_size; - char vendor[100] = "unknown"; + char *cp, *end, vendor[100] = "unknown"; + extern char saved_command_line[]; int i; + /* it's too early to be able to use the standard kernel command line support... */ + for (cp = saved_command_line; *cp; ) { + if (memcmp(cp, "mem=", 4) == 0) { + cp += 4; + mem_limit = memparse(cp, &end); + if (end != cp) + break; + cp = end; + } else { + while (*cp != ' ' && *cp) + ++cp; + while (*cp == ' ') + ++cp; + } + } + if (mem_limit != ~0UL) + printk("Ignoring memory above %luMB\n", mem_limit >> 20); + efi.systab = __va(ia64_boot_param.efi_systab); /* @@ -359,7 +378,7 @@ } #endif - map_pal_code(); + efi_map_pal_code(); } void diff -urN linux-2.4.0-test4/arch/ia64/kernel/efi_stub.S linux-2.4.0-test4-lia/arch/ia64/kernel/efi_stub.S --- linux-2.4.0-test4/arch/ia64/kernel/efi_stub.S Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/efi_stub.S Thu Jul 13 15:54:09 2000 @@ -76,17 +76,14 @@ andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared mov out3=in4 br.call.sptk.few rp=ia64_switch_mode -.ret0: - mov out4=in5 +.ret0: mov out4=in5 mov out5=in6 mov out6=in7 br.call.sptk.few rp=b6 // call the EFI function -.ret1: - mov ar.rsc=r0 // put RSE in enforced lazy, LE mode +.ret1: mov ar.rsc=r0 // put RSE in enforced lazy, LE mode mov r16=loc3 br.call.sptk.few rp=ia64_switch_mode // return to virtual mode -.ret2: - mov ar.rsc=loc4 // restore RSE configuration +.ret2: mov ar.rsc=loc4 // restore RSE configuration mov ar.pfs=loc1 mov rp=loc0 mov gp=loc2 diff -urN linux-2.4.0-test4/arch/ia64/kernel/entry.S linux-2.4.0-test4-lia/arch/ia64/kernel/entry.S --- linux-2.4.0-test4/arch/ia64/kernel/entry.S Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/entry.S Fri Jul 28 23:04:23 2000 @@ -17,8 +17,6 @@ * pSys: See entry.h. * pNonSys: !pSys * p2: (Alias of pKern!) True if any signals are pending. - * p16/p17: Used by stubs calling ia64_do_signal to indicate if current task - * has PF_PTRACED flag bit set. p16 is true if so, p17 is the complement. */ #include @@ -62,27 +60,41 @@ br.ret.sptk.few rp END(ia64_execve) -GLOBAL_ENTRY(sys_clone) +GLOBAL_ENTRY(sys_clone2) UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) - alloc r16=ar.pfs,2,2,3,0;; - mov loc0=rp + alloc r16=ar.pfs,3,2,4,0 DO_SAVE_SWITCH_STACK + mov loc0=rp mov loc1=r16 // save ar.pfs across do_fork UNW(.body) - adds out2=IA64_SWITCH_STACK_SIZE+16,sp - adds r2=IA64_SWITCH_STACK_SIZE+IA64_PT_REGS_R12_OFFSET+16,sp - cmp.eq p8,p9=in1,r0 // usp == 0? + mov out1=in1 + mov out2=in2 + adds out3=IA64_SWITCH_STACK_SIZE+16,sp // out3 = ®s mov out0=in0 // out0 = clone_flags - ;; -(p8) ld8 out1=[r2] // fetch usp from pt_regs.r12 -(p9) mov out1=in1 br.call.sptk.few rp=do_fork -.ret1: +.ret1: UNW(.restore sp) + adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov ar.pfs=loc1 - UNW(.restore sp) + mov rp=loc0 + br.ret.sptk.many rp +END(sys_clone2) + +GLOBAL_ENTRY(sys_clone) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) + alloc r16=ar.pfs,2,2,4,0 + DO_SAVE_SWITCH_STACK + mov loc0=rp + mov loc1=r16 // save ar.pfs across do_fork + UNW(.body) + mov out1=in1 + mov out2=0 + adds out3=IA64_SWITCH_STACK_SIZE+16,sp // out3 = ®s + mov out0=in0 // out0 = clone_flags + br.call.sptk.few rp=do_fork +.ret2: UNW(.restore sp) adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack + mov ar.pfs=loc1 mov rp=loc0 - ;; br.ret.sptk.many rp END(sys_clone) @@ -94,29 +106,19 @@ alloc r16=ar.pfs,1,0,0,0 DO_SAVE_SWITCH_STACK UNW(.body) - // disable interrupts to ensure atomicity for next few instructions: - mov r17=psr // M-unit - ;; - rsm psr.i // M-unit - dep r18=-1,r0,0,61 // build mask 0x1fffffffffffffff - ;; - srlz.d - ;; + adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13 + dep r18=-1,r0,0,61 // build mask 0x1fffffffffffffff adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 ;; st8 [r22]=sp // save kernel stack pointer of old task ld8 sp=[r21] // load kernel stack pointer of new task and r20=in0,r18 // physical address of "current" ;; + mov ar.k6=r20 // copy "current" into ar.k6 mov r8=r13 // return pointer to previously running task mov r13=in0 // set "current" pointer - mov ar.k6=r20 // copy "current" into ar.k6 - ;; - // restore interrupts - mov psr.l=r17 ;; - srlz.d DO_LOAD_SWITCH_STACK( ) br.ret.sptk.few rp END(ia64_switch_to) @@ -387,9 +389,9 @@ ;; // WAW on CFM at the br.call mov loc0=rp br.call.sptk.many rp=save_switch_stack_with_current_frame // must preserve b6!! -.ret2: mov loc2=b6 +.ret4: mov loc2=b6 br.call.sptk.few rp=syscall_trace -.ret3: adds sp=IA64_SWITCH_STACK_SIZE,sp // drop switch_stack frame +.ret5: adds sp=IA64_SWITCH_STACK_SIZE,sp // drop switch_stack frame mov rp=loc0 mov ar.pfs=loc1 mov b6=loc2 @@ -408,26 +410,14 @@ // r15 = syscall number // b6 = syscall entry point // - .global ia64_trace_syscall .global ia64_strace_leave_kernel -GLOBAL_ENTRY(ia64_strace_clear_r8) - // this is where we return after cloning when PF_TRACESYS is on - PT_REGS_UNWIND_INFO(0) -# ifdef CONFIG_SMP - br.call.sptk.few rp=invoke_schedule_tail -# endif - mov r8=0 - br strace_check_retval -END(ia64_strace_clear_r8) - -ENTRY(ia64_trace_syscall) +GLOBAL_ENTRY(ia64_trace_syscall) PT_REGS_UNWIND_INFO(0) br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args -.ret4: br.call.sptk.few rp=b6 // do the syscall +.ret6: br.call.sptk.few rp=b6 // do the syscall strace_check_retval: -.ret5: cmp.lt p6,p0=r8,r0 // syscall failed? - ;; + cmp.lt p6,p0=r8,r0 // syscall failed? adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 adds r3=IA64_PT_REGS_R8_OFFSET+32,sp // r3 = &pt_regs.r10 mov r10=0 @@ -438,7 +428,7 @@ .mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 ia64_strace_leave_kernel: br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value -.ret6: br.cond.sptk.many ia64_leave_kernel +.rety: br.cond.sptk.many ia64_leave_kernel strace_error: ld8 r3=[r2] // load pt_regs.r8 @@ -468,18 +458,24 @@ #define rKRBS r22 #define rB6 r21 -GLOBAL_ENTRY(ia64_ret_from_syscall_clear_r8) +GLOBAL_ENTRY(ia64_ret_from_clone) PT_REGS_UNWIND_INFO(0) #ifdef CONFIG_SMP // In SMP mode, we need to call schedule_tail to complete the scheduling process. // Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the // address of the previously executing task. br.call.sptk.few rp=invoke_schedule_tail -.ret7: -#endif +.ret8: +#endif + adds r2=IA64_TASK_PTRACE_OFFSET,r13 + ;; + ld8 r2=[r2] + ;; mov r8=0 + tbit.nz p6,p0=r2,PT_TRACESYS_BIT +(p6) br strace_check_retval ;; // added stop bits to prevent r8 dependency -END(ia64_ret_from_syscall_clear_r8) +END(ia64_ret_from_clone) // fall through GLOBAL_ENTRY(ia64_ret_from_syscall) PT_REGS_UNWIND_INFO(0) @@ -542,6 +538,7 @@ 2: // check & deliver pending signals: (p2) br.call.spnt.few rp=handle_signal_delivery +.ret9: #if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_IA64_SOFTSDV_HACKS) // Check for lost ticks rsm psr.i @@ -555,6 +552,7 @@ ;; cmp.ge p6,p7 = r2, r0 (p6) br.call.spnt.few rp=invoke_ia64_reset_itm +.ret10: ;; ssm psr.i #endif @@ -749,8 +747,7 @@ mov out0=r8 // Address of previous task ;; br.call.sptk.few rp=schedule_tail -.ret8: - mov ar.pfs=loc1 +.ret11: mov ar.pfs=loc1 mov rp=loc0 br.ret.sptk.many rp END(invoke_schedule_tail) @@ -766,7 +763,7 @@ ;; UNW(.body) br.call.sptk.many rp=ia64_reset_itm - ;; +.ret12: ;; mov ar.pfs=loc1 mov rp=loc0 br.ret.sptk.many rp @@ -785,8 +782,7 @@ ;; UNW(.body) br.call.sptk.few rp=do_softirq -.ret9: - mov ar.pfs=loc1 +.ret13: mov ar.pfs=loc1 mov rp=loc0 br.ret.sptk.many rp END(invoke_do_softirq) @@ -802,8 +798,7 @@ ;; UNW(.body) br.call.sptk.few rp=schedule -.ret10: - mov ar.pfs=loc1 +.ret14: mov ar.pfs=loc1 mov rp=loc0 br.ret.sptk.many rp END(invoke_schedule) @@ -829,8 +824,7 @@ st8 [sp]=r9,-16 // allocate space for ar.unat and save it .body br.call.sptk.few rp=ia64_do_signal -.ret11: - .restore sp +.ret15: .restore sp adds sp=16,sp // pop scratch stack space ;; ld8 r9=[sp] // load new unat from sw->caller_unat @@ -851,8 +845,7 @@ (pSys) mov out2=1 // out2==1 => we're in a syscall (pNonSys) mov out2=0 // out2==0 => not a syscall br.call.sptk.few rp=ia64_do_signal -.ret11: - // restore the switch stack (ptrace may have modified it) +.ret16: // restore the switch stack (ptrace may have modified it) DO_LOAD_SWITCH_STACK( ) br.ret.sptk.many rp #endif /* !CONFIG_IA64_NEW_UNWIND */ @@ -873,8 +866,7 @@ st8 [sp]=r9,-16 // allocate space for ar.unat and save it .body br.call.sptk.few rp=ia64_rt_sigsuspend -.ret12: - .restore sp +.ret17: .restore sp adds sp=16,sp // pop scratch stack space ;; ld8 r9=[sp] // load new unat from sw->caller_unat @@ -893,8 +885,7 @@ mov out1=in1 // sigsetsize adds out2=16,sp // out1=&sigscratch br.call.sptk.many rp=ia64_rt_sigsuspend -.ret12: - // restore the switch stack (ptrace may have modified it) +.ret18: // restore the switch stack (ptrace may have modified it) DO_LOAD_SWITCH_STACK( ) br.ret.sptk.many rp #endif /* !CONFIG_IA64_NEW_UNWIND */ @@ -912,8 +903,7 @@ ;; adds out0=16,sp // out0 = &sigscratch br.call.sptk.few rp=ia64_rt_sigreturn -.ret13: - adds sp=16,sp // doesn't drop pt_regs, so don't mark it as restoring sp! +.ret19: adds sp=16,sp // doesn't drop pt_regs, so don't mark it as restoring sp! PT_REGS_UNWIND_INFO(0) // instead, create a new body section with the smaller frame ;; ld8 r9=[sp] // load new ar.unat @@ -937,8 +927,7 @@ adds out0=16,sp // out0 = &sigscratch br.call.sptk.few rp=ia64_rt_sigreturn -.ret13: - adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp +.ret20: adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp ;; ld8 r9=[r3] // load new ar.unat mov b7=r8 @@ -957,9 +946,10 @@ // PT_REGS_UNWIND_INFO(0) mov r16=r0 + UNW(.prologue) DO_SAVE_SWITCH_STACK br.call.sptk.few rp=ia64_handle_unaligned // stack frame setup in ivt -.ret14: +.ret21: .body DO_LOAD_SWITCH_STACK(PT_REGS_UNWIND_INFO(0)) br.cond.sptk.many rp // goes to ia64_leave_kernel END(ia64_prepare_handle_unaligned) @@ -1206,7 +1196,7 @@ data8 sys_newstat // 1210 data8 sys_newlstat data8 sys_newfstat - data8 ia64_ni_syscall + data8 sys_clone2 data8 ia64_ni_syscall data8 ia64_ni_syscall // 1215 data8 ia64_ni_syscall diff -urN linux-2.4.0-test4/arch/ia64/kernel/fw-emu.c linux-2.4.0-test4-lia/arch/ia64/kernel/fw-emu.c --- linux-2.4.0-test4/arch/ia64/kernel/fw-emu.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/fw-emu.c Thu Jul 13 15:54:09 2000 @@ -240,7 +240,7 @@ if (index == SAL_FREQ_BASE) { switch (in1) { case SAL_FREQ_BASE_PLATFORM: - r9 = 100000000; + r9 = 200000000; break; case SAL_FREQ_BASE_INTERVAL_TIMER: diff -urN linux-2.4.0-test4/arch/ia64/kernel/gate.S linux-2.4.0-test4-lia/arch/ia64/kernel/gate.S --- linux-2.4.0-test4/arch/ia64/kernel/gate.S Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/gate.S Thu Jul 13 15:54:09 2000 @@ -120,8 +120,7 @@ stf.spill [base0]=f14,32 stf.spill [base1]=f15,32 br.call.sptk.few rp=b6 // call the signal handler -.ret2: - adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp +.ret0: adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp ;; ld8 r15=[base0],(CFM_OFF-BSP_OFF) // fetch sc_ar_bsp and advance to CFM_OFF mov r14=ar.bsp diff -urN linux-2.4.0-test4/arch/ia64/kernel/head.S linux-2.4.0-test4-lia/arch/ia64/kernel/head.S --- linux-2.4.0-test4/arch/ia64/kernel/head.S Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/head.S Thu Jul 13 15:54:09 2000 @@ -139,7 +139,7 @@ ;; #ifdef CONFIG_SMP (isAP) br.call.sptk.few rp=smp_callin -.ret1: +.ret0: (isAP) br.cond.sptk.few self #endif @@ -150,11 +150,10 @@ #ifdef CONFIG_IA64_FW_EMU // initialize PAL & SAL emulator: br.call.sptk.few rp=sys_fw_init - ;; +.ret1: #endif br.call.sptk.few rp=start_kernel -.ret2: - addl r2=@ltoff(halt_msg),gp +.ret2: addl r2=@ltoff(halt_msg),gp ;; ld8 out0=[r2] br.call.sptk.few b0=console_print diff -urN linux-2.4.0-test4/arch/ia64/kernel/irq_ia64.c linux-2.4.0-test4-lia/arch/ia64/kernel/irq_ia64.c --- linux-2.4.0-test4/arch/ia64/kernel/irq_ia64.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/irq_ia64.c Fri Jul 28 23:08:34 2000 @@ -117,6 +117,13 @@ { unsigned long bsp, sp; + /* + * Note: if the interrupt happened while executing in + * the context switch routine (ia64_switch_to), we may + * get a spurious stack overflow here. This is + * because the register and the memory stack are not + * switched atomically. + */ asm ("mov %0=ar.bsp" : "=r"(bsp)); asm ("mov %0=sp" : "=r"(sp)); diff -urN linux-2.4.0-test4/arch/ia64/kernel/ivt.S linux-2.4.0-test4-lia/arch/ia64/kernel/ivt.S --- linux-2.4.0-test4/arch/ia64/kernel/ivt.S Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/ivt.S Fri Jul 28 23:07:09 2000 @@ -170,32 +170,27 @@ * The ITLB basically does the same as the VHPT handler except * that we always insert exactly one instruction TLB entry. */ -#if 0 /* - * This code works, but I don't want to enable it until I have numbers - * that prove this to be a win. + * Attempt to lookup PTE through virtual linear page table. + * The speculative access will fail if there is no TLB entry + * for the L3 page table page we're trying to access. */ - mov r31=pr // save predicates - ;; - thash r17=r16 // compute virtual address of L3 PTE + mov r16=cr.iha // get virtual address of L3 PTE ;; - ld8.s r18=[r17] // try to read L3 PTE + ld8.s r16=[r16] // try to read L3 PTE + mov r31=pr // save predicates ;; - tnat.nz p6,p0=r18 // did read succeed? + tnat.nz p6,p0=r16 // did read succeed? (p6) br.cond.spnt.many 1f ;; - itc.i r18 + itc.i r16 ;; mov pr=r31,-1 rfi -1: rsm psr.dt // use physical addressing for data -#else - mov r16=cr.ifa // get address that caused the TLB miss +1: mov r16=cr.ifa // get address that caused the TLB miss ;; rsm psr.dt // use physical addressing for data -#endif - mov r31=pr // save the predicate registers mov r19=ar.k7 // get page table base address shl r21=r16,3 // shift bit 60 into sign bit shr.u r17=r16,61 // get the region number into r17 @@ -243,32 +238,27 @@ * The DTLB basically does the same as the VHPT handler except * that we always insert exactly one data TLB entry. */ - mov r16=cr.ifa // get address that caused the TLB miss -#if 0 /* - * This code works, but I don't want to enable it until I have numbers - * that prove this to be a win. + * Attempt to lookup PTE through virtual linear page table. + * The speculative access will fail if there is no TLB entry + * for the L3 page table page we're trying to access. */ - mov r31=pr // save predicates + mov r16=cr.iha // get virtual address of L3 PTE ;; - thash r17=r16 // compute virtual address of L3 PTE - ;; - ld8.s r18=[r17] // try to read L3 PTE + ld8.s r16=[r16] // try to read L3 PTE + mov r31=pr // save predicates ;; - tnat.nz p6,p0=r18 // did read succeed? + tnat.nz p6,p0=r16 // did read succeed? (p6) br.cond.spnt.many 1f ;; - itc.d r18 + itc.d r16 ;; mov pr=r31,-1 rfi -1: rsm psr.dt // use physical addressing for data -#else - rsm psr.dt // use physical addressing for data - mov r31=pr // save the predicate registers +1: mov r16=cr.ifa // get address that caused the TLB miss ;; -#endif + rsm psr.dt // use physical addressing for data mov r19=ar.k7 // get page table base address shl r21=r16,3 // shift bit 60 into sign bit shr.u r17=r16,61 // get the region number into r17 @@ -502,7 +492,24 @@ mov r29=b0 // save b0 in case of nested fault) ;; 1: ld8 r18=[r17] - ;; // avoid raw on r18 +#if defined(CONFIG_IA32_SUPPORT) && \ + (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC)) + // + // Erratum 85 (Access bit fault could be reported before page not present fault) + // If the PTE is indicates the page is not present, then just turn this into a + // page fault. + // + mov r31=pr // save predicates + ;; + tbit.nz p6,p0=r18,0 // page present bit set? +(p6) br.cond.sptk 1f + ;; // avoid WAW on p6 + mov pr=r31,-1 + br.cond.sptk page_fault // page wasn't present +1: mov pr=r31,-1 +#else + ;; // avoid RAW on r18 +#endif or r18=_PAGE_A,r18 // set the accessed bit mov b0=r29 // restore b0 ;; @@ -539,14 +546,6 @@ ;; srlz.d // ensure everyone knows psr.dt is off... cmp.eq p0,p7=r16,r17 // is this a system call? (p7 <- false, if so) -#if 1 - // Allow syscalls via the old system call number for the time being. This is - // so we can transition to the new syscall number in a relatively smooth - // fashion. - mov r17=0x80000 - ;; -(p7) cmp.eq.or.andcm p0,p7=r16,r17 // is this the old syscall number? -#endif (p7) br.cond.spnt.many non_syscall SAVE_MIN // uses r31; defines r2: @@ -568,7 +567,7 @@ mov r3=255 adds r15=-1024,r15 // r15 contains the syscall number---subtract 1024 - adds r2=IA64_TASK_FLAGS_OFFSET,r13 // r2 = ¤t->flags + adds r2=IA64_TASK_PTRACE_OFFSET,r13 // r2 = ¤t->ptrace ;; cmp.geu.unc p6,p7=r3,r15 // (syscall > 0 && syscall <= 1024+255) ? @@ -581,7 +580,7 @@ ld8 r16=[r16] // load address of syscall entry point mov rp=r15 // set the real return addr ;; - ld8 r2=[r2] // r2 = current->flags + ld8 r2=[r2] // r2 = current->ptrace mov b6=r16 // arrange things so we skip over break instruction when returning: @@ -590,7 +589,7 @@ adds r17=24,sp // get pointer to cr_iip ;; ld8 r18=[r16] // fetch cr_ipsr - tbit.z p8,p0=r2,5 // (current->flags & PF_TRACESYS) == 0? + tbit.z p8,p0=r2,PT_TRACESYS_BIT // (current->ptrace & PF_TRACESYS) == 0? ;; ld8 r19=[r17] // fetch cr_iip extr.u r20=r18,41,2 // extract ei field @@ -686,7 +685,7 @@ SAVE_REST ;; br.call.sptk.few rp=ia64_illegal_op_fault - ;; +.ret0: ;; alloc r14=ar.pfs,0,0,3,0 // must be first in insn group mov out0=r9 mov out1=r10 @@ -755,16 +754,16 @@ ld4 out5=[r14],8 // r13 == ebp ;; ld4 out3=[r14],8 // r14 == esi - adds r2=IA64_TASK_FLAGS_OFFSET,r13 // r2 = ¤t->flags + adds r2=IA64_TASK_PTRACE_OFFSET,r13 // r2 = ¤t->ptrace ;; ld4 out4=[r14] // R15 == edi movl r16=ia32_syscall_table ;; (p6) shladd r16=r8,3,r16 // Force ni_syscall if not valid syscall number - ld8 r2=[r2] // r2 = current->flags + ld8 r2=[r2] // r2 = current->ptrace ;; ld8 r16=[r16] - tbit.z p8,p0=r2,5 // (current->flags & PF_TRACESYS) == 0? + tbit.z p8,p0=r2,PT_TRACESYS_BIT // (current->ptrace & PT_TRACESYS) == 0? ;; mov b6=r16 movl r15=ia32_ret_from_syscall @@ -780,8 +779,7 @@ add out1=16,sp // pointer to pt_regs ;; // avoid WAW on CFM br.call.sptk.few rp=ia32_bad_interrupt - ;; - movl r15=ia64_leave_kernel +.ret1: movl r15=ia64_leave_kernel ;; mov rp=r15 br.ret.sptk.many rp diff -urN linux-2.4.0-test4/arch/ia64/kernel/machvec.c linux-2.4.0-test4-lia/arch/ia64/kernel/machvec.c --- linux-2.4.0-test4/arch/ia64/kernel/machvec.c Tue Feb 8 12:01:59 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/machvec.c Fri Jul 28 23:08:48 2000 @@ -3,12 +3,9 @@ #include #include -struct ia64_machine_vector ia64_mv; +#ifdef CONFIG_IA64_GENERIC -void -machvec_noop (void) -{ -} +struct ia64_machine_vector ia64_mv; /* * Most platforms use this routine for mapping page frame addresses @@ -45,4 +42,11 @@ } ia64_mv = *mv; printk("booting generic kernel on platform %s\n", name); +} + +#endif /* CONFIG_IA64_GENERIC */ + +void +machvec_noop (void) +{ } diff -urN linux-2.4.0-test4/arch/ia64/kernel/mca.c linux-2.4.0-test4-lia/arch/ia64/kernel/mca.c --- linux-2.4.0-test4/arch/ia64/kernel/mca.c Fri Jun 23 21:11:20 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/mca.c Thu Jul 13 15:54:09 2000 @@ -9,8 +9,7 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * - * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, - * logging issues, + * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, * added min save state dump, added INIT handler. */ #include diff -urN linux-2.4.0-test4/arch/ia64/kernel/mca_asm.S linux-2.4.0-test4-lia/arch/ia64/kernel/mca_asm.S --- linux-2.4.0-test4/arch/ia64/kernel/mca_asm.S Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/mca_asm.S Thu Jul 13 15:54:09 2000 @@ -136,8 +136,7 @@ movl r2=ia64_mca_ucmc_handler;; mov b6=r2;; br.call.sptk.few b0=b6 - ;; - +.ret0: // Revert back to physical mode before going back to SAL PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4) ia64_os_mca_virtual_end: @@ -766,7 +765,7 @@ ;; br.call.sptk.few rp=ia64_init_handler - ;; +.ret1: return_from_init: br.sptk return_from_init diff -urN linux-2.4.0-test4/arch/ia64/kernel/pal.S linux-2.4.0-test4-lia/arch/ia64/kernel/pal.S --- linux-2.4.0-test4/arch/ia64/kernel/pal.S Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/pal.S Fri Jul 28 23:08:58 2000 @@ -74,14 +74,14 @@ mov loc3 = psr mov loc0 = rp UNW(.body) - adds r8 = .ret0-1b,r8 + adds r8 = 1f-1b,r8 ;; rsm psr.i mov b7 = loc2 mov rp = r8 ;; br.cond.sptk.few b7 -.ret0: mov psr.l = loc3 +1: mov psr.l = loc3 mov ar.pfs = loc1 mov rp = loc0 ;; @@ -116,8 +116,7 @@ mov b7 = loc2 ;; br.call.sptk.many rp=b7 // now make the call -.ret2: - mov psr.l = loc3 +.ret0: mov psr.l = loc3 mov ar.pfs = loc1 mov rp = loc0 ;; @@ -161,7 +160,7 @@ mov r31 = in3 // copy arg3 ;; mov loc3 = psr // save psr - adds r8 = .ret4-1b,r8 // calculate return address for call + adds r8 = 1f-1b,r8 // calculate return address for call ;; mov loc4=ar.rsc // save RSE configuration dep.z loc2=loc2,0,61 // convert pal entry point to physical @@ -176,15 +175,14 @@ ;; andcm r16=loc3,r16 // removes bits to clear from psr br.call.sptk.few rp=ia64_switch_mode -.ret3: - mov rp = r8 // install return address (physical) +.ret1: mov rp = r8 // install return address (physical) br.cond.sptk.few b7 -.ret4: +1: mov ar.rsc=r0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr br.call.sptk.few rp=ia64_switch_mode // return to virtual mode - -.ret5: mov psr.l = loc3 // restore init PSR +.ret2: + mov psr.l = loc3 // restore init PSR mov ar.pfs = loc1 mov rp = loc0 @@ -193,3 +191,57 @@ srlz.d // seralize restoration of psr.l br.ret.sptk.few b0 END(ia64_pal_call_phys_static) + +/* + * Make a PAL call using the stacked registers in physical mode. + * + * Inputs: + * in0 Index of PAL service + * in2 - in3 Remaning PAL arguments + */ +GLOBAL_ENTRY(ia64_pal_call_phys_stacked) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)) + alloc loc1 = ar.pfs,5,5,86,0 + movl loc2 = pal_entry_point +1: { + mov r28 = in0 // copy procedure index + mov loc0 = rp // save rp + } + .body + ;; + ld8 loc2 = [loc2] // loc2 <- entry point + mov out0 = in0 // first argument + mov out1 = in1 // copy arg2 + mov out2 = in2 // copy arg3 + mov out3 = in3 // copy arg3 + ;; + mov loc3 = psr // save psr + ;; + mov loc4=ar.rsc // save RSE configuration + dep.z loc2=loc2,0,61 // convert pal entry point to physical + ;; + mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + movl r16=PAL_PSR_BITS_TO_CLEAR + movl r17=PAL_PSR_BITS_TO_SET + ;; + or loc3=loc3,r17 // add in psr the bits to set + mov b7 = loc2 // install target to branch reg + ;; + andcm r16=loc3,r16 // removes bits to clear from psr + br.call.sptk.few rp=ia64_switch_mode +.ret6: + br.call.sptk.many rp=b7 // now make the call +.ret7: + mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov r16=loc3 // r16= original psr + br.call.sptk.few rp=ia64_switch_mode // return to virtual mode + +.ret8: mov psr.l = loc3 // restore init PSR + mov ar.pfs = loc1 + mov rp = loc0 + ;; + mov ar.rsc=loc4 // restore RSE configuration + srlz.d // seralize restoration of psr.l + br.ret.sptk.few b0 +END(ia64_pal_call_phys_stacked) + diff -urN linux-2.4.0-test4/arch/ia64/kernel/palinfo.c linux-2.4.0-test4-lia/arch/ia64/kernel/palinfo.c --- linux-2.4.0-test4/arch/ia64/kernel/palinfo.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/palinfo.c Fri Jul 28 23:09:09 2000 @@ -27,13 +27,22 @@ #include #include #include +#ifdef CONFIG_SMP +#include +#endif /* * Hope to get rid of these in a near future */ #define IA64_PAL_VERSION_BUG 1 -#define PALINFO_VERSION "0.1" +#define PALINFO_VERSION "0.2" + +#ifdef CONFIG_SMP +#define cpu_is_online(i) (cpu_online_map & (1UL << i)) +#else +#define cpu_is_online(i) 1 +#endif typedef int (*palinfo_func_t)(char*); @@ -43,7 +52,6 @@ struct proc_dir_entry *entry; /* registered entry (removal) */ } palinfo_entry_t; -static struct proc_dir_entry *palinfo_dir; /* * A bunch of string array to get pretty printing @@ -95,7 +103,7 @@ #define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *)) /* - * The current resvision of the Volume 2 of + * The current revision of the Volume 2 of * IA-64 Architecture Software Developer's Manual is wrong. * Table 4-10 has invalid information concerning the ma field: * Correct table is: @@ -564,7 +572,6 @@ int i; s64 ret; - /* must be in physical mode */ if ((ret=ia64_pal_proc_get_features(&avail, &status, &control)) != 0) return 0; for(i=0; i < 64; i++, v++,avail >>=1, status >>=1, control >>=1) { @@ -577,6 +584,57 @@ return p - page; } +static const char *bus_features[]={ + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, + NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL, + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, + NULL,NULL, + "Request Bus Parking", + "Bus Lock Mask", + "Enable Half Transfer", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, + "Disable Transaction Queuing", + "Disable Reponse Error Checking", + "Disable Bus Error Checking", + "Disable Bus Requester Internal Error Signalling", + "Disable Bus Requester Error Signalling", + "Disable Bus Initialization Event Checking", + "Disable Bus Initialization Event Signalling", + "Disable Bus Address Error Checking", + "Disable Bus Address Error Signalling", + "Disable Bus Data Error Checking" +}; + + +static int +bus_info(char *page) +{ + char *p = page; + const char **v = bus_features; + pal_bus_features_u_t av, st, ct; + u64 avail, status, control; + int i; + s64 ret; + + if ((ret=ia64_pal_bus_get_features(&av, &st, &ct)) != 0) return 0; + + avail = av.pal_bus_features_val; + status = st.pal_bus_features_val; + control = ct.pal_bus_features_val; + + for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) { + if ( ! *v ) continue; + p += sprintf(p, "%-48s : %s%s %s\n", *v, + avail & 0x1 ? "" : "NotImpl", + avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "", + avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): ""); + } + return p - page; +} + + /* * physical mode call for PAL_VERSION is working fine. * This function is meant to go away once PAL get fixed. @@ -613,21 +671,19 @@ #endif if (status != 0) return 0; - p += sprintf(p, "PAL_vendor : 0x%x (min=0x%x)\n" \ - "PAL_A revision : 0x%x (min=0x%x)\n" \ - "PAL_A model : 0x%x (min=0x%x)\n" \ - "PAL_B mode : 0x%x (min=0x%x)\n" \ - "PAL_B revision : 0x%x (min=0x%x)\n", + p += sprintf(p, "PAL_vendor : 0x%02x (min=0x%02x)\n" \ + "PAL_A : %02x.%02x (min=%02x.%02x)\n" \ + "PAL_B : %02x.%02x (min=%02x.%02x)\n", cur_ver.pal_version_s.pv_pal_vendor, min_ver.pal_version_s.pv_pal_vendor, - cur_ver.pal_version_s.pv_pal_a_rev, - cur_ver.pal_version_s.pv_pal_a_rev, cur_ver.pal_version_s.pv_pal_a_model, + cur_ver.pal_version_s.pv_pal_a_rev, min_ver.pal_version_s.pv_pal_a_model, - cur_ver.pal_version_s.pv_pal_b_rev, - min_ver.pal_version_s.pv_pal_b_rev, + min_ver.pal_version_s.pv_pal_a_rev, cur_ver.pal_version_s.pv_pal_b_model, - min_ver.pal_version_s.pv_pal_b_model); + cur_ver.pal_version_s.pv_pal_b_rev, + min_ver.pal_version_s.pv_pal_b_model, + min_ver.pal_version_s.pv_pal_b_rev); return p - page; } @@ -708,30 +764,111 @@ return p - page; } - -/* - * Entry point routine: all calls go trhough this function - */ static int -palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) +tr_info(char *page) { - palinfo_func_t info = (palinfo_func_t)data; - int len = info(page); + char *p = page; + s64 status; + pal_tr_valid_u_t tr_valid; + u64 tr_buffer[4]; + pal_vm_info_1_u_t vm_info_1; + pal_vm_info_2_u_t vm_info_2; + int i, j; + u64 max[3], pgm; + struct ifa_reg { + u64 valid:1; + u64 ig:11; + u64 vpn:52; + } *ifa_reg; + struct itir_reg { + u64 rv1:2; + u64 ps:6; + u64 key:24; + u64 rv2:32; + } *itir_reg; + struct gr_reg { + u64 p:1; + u64 rv1:1; + u64 ma:3; + u64 a:1; + u64 d:1; + u64 pl:2; + u64 ar:3; + u64 ppn:38; + u64 rv2:2; + u64 ed:1; + u64 ig:11; + } *gr_reg; + struct rid_reg { + u64 ig1:1; + u64 rv1:1; + u64 ig2:6; + u64 rid:24; + u64 rv2:32; + } *rid_reg; - if (len <= off+count) *eof = 1; + if ((status=ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) { + printk("ia64_pal_vm_summary=%ld\n", status); + return 0; + } + max[0] = vm_info_1.pal_vm_info_1_s.max_itr_entry+1; + max[1] = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1; - *start = page + off; - len -= off; + for (i=0; i < 2; i++ ) { + for (j=0; j < max[i]; j++) { - if (len>count) len = count; - if (len<0) len = 0; + status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid); + if (status != 0) { + printk(__FUNCTION__ " pal call failed on tr[%d:%d]=%ld\n", i, j, status); + continue; + } - return len; + ifa_reg = (struct ifa_reg *)&tr_buffer[2]; + + if (ifa_reg->valid == 0) continue; + + gr_reg = (struct gr_reg *)tr_buffer; + itir_reg = (struct itir_reg *)&tr_buffer[1]; + rid_reg = (struct rid_reg *)&tr_buffer[3]; + + pgm = -1 << (itir_reg->ps - 12); + p += sprintf(p, "%cTR%d: av=%d pv=%d dv=%d mv=%d\n" \ + "\tppn : 0x%lx\n" \ + "\tvpn : 0x%lx\n" \ + "\tps : ", + + "ID"[i], + j, + tr_valid.pal_tr_valid_s.access_rights_valid, + tr_valid.pal_tr_valid_s.priv_level_valid, + tr_valid.pal_tr_valid_s.dirty_bit_valid, + tr_valid.pal_tr_valid_s.mem_attr_valid, + (gr_reg->ppn & pgm)<< 12, + (ifa_reg->vpn & pgm)<< 12); + + p = bitvector_process(p, 1<< itir_reg->ps); + + p += sprintf(p, "\n\tpl : %d\n" \ + "\tar : %d\n" \ + "\trid : %x\n" \ + "\tp : %d\n" \ + "\tma : %d\n" \ + "\td : %d\n", + gr_reg->pl, + gr_reg->ar, + rid_reg->rid, + gr_reg->p, + gr_reg->ma, + gr_reg->d); + } + } + return p - page; } + + /* - * List names,function pairs for every entry in /proc/palinfo - * Must be terminated with the NULL,NULL entry. + * List {name,function} pairs for every entry in /proc/palinfo/cpu* */ static palinfo_entry_t palinfo_entries[]={ { "version_info", version_info, }, @@ -742,23 +879,175 @@ { "processor_info", processor_info, }, { "perfmon_info", perfmon_info, }, { "frequency_info", frequency_info, }, - { NULL, NULL,} + { "bus_info", bus_info }, + { "tr_info", tr_info, } }; +#define NR_PALINFO_ENTRIES (sizeof(palinfo_entries)/sizeof(palinfo_entry_t)) + +/* + * this array is used to keep track of the proc entries we create. This is + * required in the module mode when we need to remove all entries. The procfs code + * does not do recursion of deletion + * + * Notes: + * - first +1 accounts for the cpuN entry + * - second +1 account for toplevel palinfo + * + */ +#define NR_PALINFO_PROC_ENTRIES (NR_CPUS*(NR_PALINFO_ENTRIES+1)+1) + +static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES]; + +/* + * This data structure is used to pass which cpu,function is being requested + * It must fit in a 64bit quantity to be passed to the proc callback routine + * + * In SMP mode, when we get a request for another CPU, we must call that + * other CPU using IPI and wait for the result before returning. + */ +typedef union { + u64 value; + struct { + unsigned req_cpu: 32; /* for which CPU this info is */ + unsigned func_id: 32; /* which function is requested */ + } pal_func_cpu; +} pal_func_cpu_u_t; + +#define req_cpu pal_func_cpu.req_cpu +#define func_id pal_func_cpu.func_id + +#ifdef CONFIG_SMP + +/* + * used to hold information about final function to call + */ +typedef struct { + palinfo_func_t func; /* pointer to function to call */ + char *page; /* buffer to store results */ + int ret; /* return value from call */ +} palinfo_smp_data_t; + + +/* + * this function does the actual final call and he called + * from the smp code, i.e., this is the palinfo callback routine + */ +static void +palinfo_smp_call(void *info) +{ + palinfo_smp_data_t *data = (palinfo_smp_data_t *)info; + /* printk(__FUNCTION__" called on CPU %d\n", smp_processor_id());*/ + if (data == NULL) { + printk(KERN_ERR __FUNCTION__" data pointer is NULL\n"); + data->ret = 0; /* no output */ + return; + } + /* does this actual call */ + data->ret = (*data->func)(data->page); +} + +/* + * function called to trigger the IPI, we need to access a remote CPU + * Return: + * 0 : error or nothing to output + * otherwise how many bytes in the "page" buffer were written + */ +static +int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) +{ + palinfo_smp_data_t ptr; + int ret; + + ptr.func = palinfo_entries[f->func_id].proc_read; + ptr.page = page; + ptr.ret = 0; /* just in case */ + + /*printk(__FUNCTION__" calling CPU %d from CPU %d for function %d\n", f->req_cpu,smp_processor_id(), f->func_id);*/ + + /* will send IPI to other CPU and wait for completion of remote call */ + if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) { + printk(__FUNCTION__" remote CPU call from %d to %d on function %d: error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret); + return 0; + } + return ptr.ret; +} +#else /* ! CONFIG_SMP */ +static +int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) +{ + printk(__FUNCTION__" should not be called with non SMP kernel\n"); + return 0; +} +#endif /* CONFIG_SMP */ + +/* + * Entry point routine: all calls go through this function + */ +static int +palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len=0; + pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&data; + + /* + * in SMP mode, we may need to call another CPU to get correct + * information. PAL, by definition, is processor specific + */ + if (f->req_cpu == smp_processor_id()) + len = (*palinfo_entries[f->func_id].proc_read)(page); + else + len = palinfo_handle_smp(f, page); + + if (len <= off+count) *eof = 1; + + *start = page + off; + len -= off; + + if (len>count) len = count; + if (len<0) len = 0; + + return len; +} static int __init palinfo_init(void) { +# define CPUSTR "cpu%d" + palinfo_entry_t *p; + pal_func_cpu_u_t f; + struct proc_dir_entry **pdir = palinfo_proc_entries; + struct proc_dir_entry *palinfo_dir, *cpu_dir; + int i, j; + char cpustr[sizeof(CPUSTR)]; printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION); - palinfo_dir = create_proc_entry("palinfo", S_IFDIR | S_IRUGO | S_IXUGO, NULL); + palinfo_dir = proc_mkdir("pal", NULL); - for (p = palinfo_entries; p->name ; p++){ - p->entry = create_proc_read_entry (p->name, 0, palinfo_dir, - palinfo_read_entry, p->proc_read); + /* + * we keep track of created entries in a depth-first order for + * cleanup purposes. Each entry is stored into palinfo_proc_entries + */ + for (i=0; i < NR_CPUS; i++) { + + if (!cpu_is_online(i)) continue; + + sprintf(cpustr,CPUSTR, i); + + cpu_dir = proc_mkdir(cpustr, palinfo_dir); + + f.req_cpu = i; + + for (j=0; j < NR_PALINFO_ENTRIES; j++) { + f.func_id = j; + *pdir++ = create_proc_read_entry (palinfo_entries[j].name, 0, cpu_dir, + palinfo_read_entry, (void *)f.value); + } + *pdir++ = cpu_dir; } + *pdir = palinfo_dir; return 0; } @@ -766,12 +1055,12 @@ static int __exit palinfo_exit(void) { - palinfo_entry_t *p; + int i = 0; - for (p = palinfo_entries; p->name ; p++){ - remove_proc_entry (p->name, palinfo_dir); + /* remove all nodes: depth first pass */ + for (i=0; i< NR_PALINFO_PROC_ENTRIES ; i++) { + remove_proc_entry (palinfo_proc_entries[i]->name, NULL); } - remove_proc_entry ("palinfo", 0); return 0; } diff -urN linux-2.4.0-test4/arch/ia64/kernel/pci-dma.c linux-2.4.0-test4-lia/arch/ia64/kernel/pci-dma.c --- linux-2.4.0-test4/arch/ia64/kernel/pci-dma.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/pci-dma.c Fri Jul 28 23:10:22 2000 @@ -3,34 +3,424 @@ * * This implementation is for IA-64 platforms that do not support * I/O TLBs (aka DMA address translation hardware). - * - * XXX This doesn't do the right thing yet. It appears we would have - * to add additional zones so we can implement the various address - * mask constraints that we might encounter. A zone for memory < 32 - * bits is obviously necessary... + * Goutham Rao : Implemented the PCI DMA mapping API. */ -#include +#include + #include -#include #include +#include +#include +#include #include +#include +#include + +#ifdef CONFIG_SWIOTLB + +#include +#include + +#define ALIGN(val, align) ((void *) (((unsigned long) (val) + ((align) - 1)) & ~((align) - 1))) + +typedef struct io_tlb_sizes { + size_t size; + int log_size; + int n_buffers; + int curr_index; + spinlock_t lock; + char *base; + unsigned long *orig_addr; + unsigned int *free_list; +} io_tlb_sizes_t; + +/* + * List entries in order of size (low to high) + */ +static io_tlb_sizes_t io_tlb[] = { + {2048, 11, 128, 127, SPIN_LOCK_UNLOCKED, 0, 0, 0}, + {PAGE_SIZE, PAGE_SHIFT, 128, 127, SPIN_LOCK_UNLOCKED, 0, 0, 0}, + /* + * Indicated end of entries + */ + {0, 0, 0, 0, SPIN_LOCK_UNLOCKED, 0, 0, 0} +}; + +/* + * Used to do a quick range check in pci_unmap_single and pci_sync_single + */ +static char *io_tlb_start, *io_tlb_end; + +static unsigned long swiotlb_buf_count; + +static int __init +setup_swiotlb_buf_count (char *str) +{ + swiotlb_buf_count = simple_strtoul(str, NULL, 0); + return 1; +} + +__setup("swiotlb=", setup_swiotlb_buf_count); + +/* + * Statically reserve bounce buffer space and initialize bounce buffer + * data structures for the software IO TLB used to implement the PCI DMA API + */ +void +setup_swiotlb (void) +{ + unsigned long entry_size, size = 0; + struct io_tlb_sizes *itp; + + for (itp = io_tlb; itp->size; ++itp) { + /* + * Let user override number of buffers needed + */ + if (swiotlb_buf_count) + itp->n_buffers = swiotlb_buf_count; + itp->curr_index = itp->n_buffers - 1; + /* + * size needed for buffers + size needed for offset + * table + size needed for mapping: + */ + entry_size = itp->size + sizeof(int) + sizeof(long); + /* the +1 makes room for the worst-case alignment... */ + size += (itp->n_buffers + 1)*entry_size; + } + + /* + * Now get IO TLB memory from the low pages + */ + io_tlb_start = io_tlb_end = alloc_bootmem_low_pages(size); + if (!io_tlb_start) + BUG(); + + /* + * For every io tlb size entry, allocate the required amount of memory + * and initialize the free list array to mark all entries as available + */ + for (itp = io_tlb; itp->size; ++itp) { + int j; + + /* + * Reserve memory for the IO TLB buffers and the + * offsets array for these size chunks + */ + itp->base = ALIGN(io_tlb_end, itp->size); + io_tlb_end = itp->base + itp->size * itp->n_buffers; + + itp->orig_addr = ALIGN(io_tlb_end, sizeof(long)); + io_tlb_end = ((char *)itp->orig_addr) + itp->n_buffers * sizeof(long); + + itp->free_list = (unsigned int *)io_tlb_end; + io_tlb_end = ((char *)itp->free_list) + itp->n_buffers * sizeof(int); + + /* + * Initialize free list array, marking all entries available + */ + for (j = 0; j < itp->n_buffers; j++) + itp->free_list[j] = (unsigned int)(j * itp->size); + } + printk("Placing software IO TLB between 0x%p - 0x%p\n", io_tlb_start, io_tlb_end); +} + +/* + * Allocates bounce buffer and returns its kernel virtual address. + */ +static void * +__pci_map_single (struct pci_dev *hwdev, char *buffer, size_t size, int direction) +{ + struct io_tlb_sizes *itp; + char *dma_addr = 0; + int index; + + /* + * Find a IO TLB size that will fit this request and allocate a buffer + * from that IO TLB pool. + */ + for (itp = io_tlb; itp->size; ++itp) { + if (size <= itp->size) { + unsigned long flags; + + spin_lock_irqsave(&itp->lock, flags); + { + if (!itp->curr_index) { + /* + * Get buffer from next IO TLB... this will + * waste memory though. + */ + spin_unlock_irqrestore(&itp->lock, flags); + continue; + } + dma_addr = (itp->base + itp->free_list[itp->curr_index--]); + } + spin_unlock_irqrestore(&itp->lock, flags); + /* + * Save the mapping from original address to DMA address + * because the map_single API doesen't have a mapping + * like the map_sg API. + */ + index = (dma_addr - itp->base) >> itp->log_size; + itp->orig_addr[index] = (unsigned long) buffer; + + if (direction == PCI_DMA_TODEVICE || direction == PCI_DMA_BIDIRECTIONAL) + memcpy(dma_addr, buffer, size); + + return dma_addr; + } + } + + /* + * XXX What is a suitable recovery mechanism here? We cannot + * sleep because we are called from with in interrupts! + */ + panic("__pci_map_single: could not allocate software IO TLB (%ld bytes)", size); +} + +/* + * dma_addr is the kernel virtual address of the bounce buffer to unmap. + */ +static void +__pci_unmap_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction) +{ + struct io_tlb_sizes *itp; + + /* + * Return the buffer to the free list + */ + for (itp = io_tlb; itp->size; ++itp) { + if (size <= itp->size) { + unsigned long flags; + char *buffer; + int index; + + /* + * Get the mapping (IO address to original address)... + */ + index = (dma_addr - itp->base) >> itp->log_size; + buffer = (char *) itp->orig_addr[index]; + if ((direction == PCI_DMA_FROMDEVICE) + || (direction == PCI_DMA_BIDIRECTIONAL)) + /* + * bounce... copy the data back into the original buffer + * and delete the bounce buffer. + */ + memcpy(buffer, dma_addr, size); + + /* + * Return the entry to the list + */ + spin_lock_irqsave(&itp->lock, flags); + { + itp->free_list[++itp->curr_index] = (dma_addr - itp->base); + } + spin_unlock_irqrestore(&itp->lock, flags); + return; + } + } + BUG(); +} + +static void +__pci_sync_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction) +{ + struct io_tlb_sizes *itp; + char *buffer; + int index; + + /* + * bounce... copy the data back into/from the original buffer + * XXX How do you handle PCI_DMA_BIDIRECTIONAL here ? + */ + for (itp = io_tlb; itp->size; ++itp) { + if (size <= itp->size) { + /* + * Get the mapping (IO address to original address)... + */ + index = (dma_addr - itp->base) >> itp->log_size; + buffer = (char *) itp->orig_addr[index]; + if (direction == PCI_DMA_FROMDEVICE) + memcpy(buffer, dma_addr, size); + else if (direction == PCI_DMA_TODEVICE) + memcpy(dma_addr, buffer, size); + else + BUG(); + break; + } + } +} + +/* + * Map a single buffer of the indicated size for DMA in streaming mode. + * The PCI address to use is returned. + * + * Once the device is given the dma address, the device owns this memory + * until either pci_unmap_single or pci_dma_sync_single is performed. + */ +dma_addr_t +pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction) +{ + unsigned long pci_addr = virt_to_phys(ptr); + + if (direction == PCI_DMA_NONE) + BUG(); + /* + * Check if the PCI device can DMA to ptr... if so, just return ptr + */ + if ((pci_addr & ~hwdev->dma_mask) == 0) + /* + * Device is bit capable of DMA'ing to the + * buffer... just return the PCI address of ptr + */ + return pci_addr; + + /* get a bounce buffer: */ + + pci_addr = virt_to_phys(__pci_map_single(hwdev, ptr, size, direction)); + /* + * Ensure that the address returned is DMA'ble: + */ + if ((pci_addr & ~hwdev->dma_mask) != 0) + panic("__pci_map_single: bounce buffer is not DMA'ble"); + + return pci_addr; +} + +/* + * Unmap a single streaming mode DMA translation. The dma_addr and size + * must match what was provided for in a previous pci_map_single call. All + * other usages are undefined. + * + * After this call, reads by the cpu to the buffer are guarenteed to see + * whatever the device wrote there. + */ +void +pci_unmap_single (struct pci_dev *hwdev, dma_addr_t pci_addr, size_t size, int direction) +{ + char *dma_addr = phys_to_virt(pci_addr); + + if (direction == PCI_DMA_NONE) + BUG(); + if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) + __pci_unmap_single(hwdev, dma_addr, size, direction); +} + +/* + * Make physical memory consistent for a single + * streaming mode DMA translation after a transfer. + * + * If you perform a pci_map_single() but wish to interrogate the + * buffer using the cpu, yet do not wish to teardown the PCI dma + * mapping, you must call this function before doing so. At the + * next point you give the PCI dma address back to the card, the + * device again owns the buffer. + */ +void +pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t pci_addr, size_t size, int direction) +{ + char *dma_addr = phys_to_virt(pci_addr); + + if (direction == PCI_DMA_NONE) + BUG(); + if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) + __pci_sync_single(hwdev, dma_addr, size, direction); +} + +/* + * Map a set of buffers described by scatterlist in streaming + * mode for DMA. This is the scather-gather version of the + * above pci_map_single interface. Here the scatter gather list + * elements are each tagged with the appropriate dma address + * and length. They are obtained via sg_dma_{address,length}(SG). + * + * NOTE: An implementation may be able to use a smaller number of + * DMA address/length pairs than there are SG table elements. + * (for example via virtual mapping capabilities) + * The routine returns the number of addr/length pairs actually + * used, at most nents. + * + * Device ownership issues as mentioned above for pci_map_single are + * the same here. + */ +int +pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +{ + int i; + + if (direction == PCI_DMA_NONE) + BUG(); + + for (i = 0; i < nelems; i++, sg++) { + sg->orig_address = sg->address; + if ((virt_to_phys(sg->address) & ~hwdev->dma_mask) != 0) { + sg->address = __pci_map_single(hwdev, sg->address, sg->length, direction); + } + } + return nelems; +} + +/* + * Unmap a set of streaming mode DMA translations. + * Again, cpu read rules concerning calls here are the same as for + * pci_unmap_single() above. + */ +void +pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +{ + int i; + + if (direction == PCI_DMA_NONE) + BUG(); + + for (i = 0; i < nelems; i++, sg++) + if (sg->orig_address != sg->address) { + __pci_unmap_single(hwdev, sg->address, sg->length, direction); + sg->address = sg->orig_address; + } +} + +/* + * Make physical memory consistent for a set of streaming mode DMA + * translations after a transfer. + * + * The same as pci_dma_sync_single but for a scatter-gather list, + * same rules and usage. + */ +void +pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +{ + int i; + + if (direction == PCI_DMA_NONE) + BUG(); + + for (i = 0; i < nelems; i++, sg++) + if (sg->orig_address != sg->address) + __pci_sync_single(hwdev, sg->address, sg->length, direction); +} + +#endif /* CONFIG_SWIOTLB */ void * pci_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { - void *ret; + unsigned long pci_addr; int gfp = GFP_ATOMIC; + void *ret; - if (!hwdev || hwdev->dma_mask == 0xffffffff) - gfp |= GFP_DMA; /* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */ + if (!hwdev || hwdev->dma_mask <= 0xffffffff) + gfp |= GFP_DMA; /* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */ ret = (void *)__get_free_pages(gfp, get_order(size)); + if (!ret) + return NULL; - if (ret) { - memset(ret, 0, size); - *dma_handle = virt_to_bus(ret); - } + memset(ret, 0, size); + pci_addr = virt_to_phys(ret); + if ((pci_addr & ~hwdev->dma_mask) != 0) + panic("pci_alloc_consistent: allocated memory is out of range for PCI device"); + *dma_handle = pci_addr; return ret; } diff -urN linux-2.4.0-test4/arch/ia64/kernel/process.c linux-2.4.0-test4-lia/arch/ia64/kernel/process.c --- linux-2.4.0-test4/arch/ia64/kernel/process.c Mon Jul 10 13:16:56 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/process.c Fri Jul 28 23:10:40 2000 @@ -1,8 +1,8 @@ /* * Architecture-specific setup. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang */ #define __KERNEL_SYSCALLS__ /* see */ #include @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -204,24 +205,22 @@ * be copied as well. * * Observe that we copy the unat values that are in pt_regs and - * switch_stack. Since the interpretation of unat is dependent upon - * the address to which the registers got spilled, doing this is valid - * only as long as we preserve the alignment of the stack. Since the - * stack is always page aligned, we know this is the case. - * - * XXX Actually, the above isn't true when we create kernel_threads(). - * If we ever needs to create kernel_threads() that preserve the unat - * values we'll need to fix this. Perhaps an easy workaround would be - * to always clear the unat bits in the child thread. + * switch_stack. Spilling an integer to address X causes bit N in + * ar.unat to be set to the NaT bit of the register, with N=(X & + * 0x1ff)/8. Thus, copying the unat value preserves the NaT bits ONLY + * if the pt_regs structure in the parent is congruent to that of the + * child, modulo 512. Since the stack is page aligned and the page + * size is at least 4KB, this is always the case, so there is nothing + * to worry about. */ int -copy_thread (int nr, unsigned long clone_flags, unsigned long usp, +copy_thread (int nr, unsigned long clone_flags, + unsigned long user_stack_base, unsigned long user_stack_size, struct task_struct *p, struct pt_regs *regs) { unsigned long rbs, child_rbs, rbs_size, stack_offset, stack_top, stack_used; struct switch_stack *child_stack, *stack; - extern char ia64_ret_from_syscall_clear_r8; - extern char ia64_strace_clear_r8; + extern char ia64_ret_from_clone; struct pt_regs *child_ptregs; #ifdef CONFIG_SMP @@ -251,10 +250,14 @@ /* copy the parent's register backing store to the child: */ memcpy((void *) child_rbs, (void *) rbs, rbs_size); - child_ptregs->r8 = 0; /* child gets a zero return value */ - if (user_mode(child_ptregs)) - child_ptregs->r12 = usp; /* user stack pointer */ - else { + if (user_mode(child_ptregs)) { + if (user_stack_base) { + child_ptregs->r12 = user_stack_base + user_stack_size; + child_ptregs->ar_bspstore = user_stack_base; + child_ptregs->ar_rnat = 0; + child_ptregs->loadrs = 0; + } + } else { /* * Note: we simply preserve the relative position of * the stack pointer here. There is no need to @@ -265,13 +268,10 @@ child_ptregs->r12 = (unsigned long) (child_ptregs + 1); /* kernel sp */ child_ptregs->r13 = (unsigned long) p; /* set `current' pointer */ } - if (p->flags & PF_TRACESYS) - child_stack->b0 = (unsigned long) &ia64_strace_clear_r8; - else - child_stack->b0 = (unsigned long) &ia64_ret_from_syscall_clear_r8; + child_stack->b0 = (unsigned long) &ia64_ret_from_clone; child_stack->ar_bspstore = child_rbs + rbs_size; - /* copy the thread_struct: */ + /* copy parts of thread_struct: */ p->thread.ksp = (unsigned long) child_stack - 16; /* * NOTE: The calling convention considers all floating point @@ -288,18 +288,11 @@ * would be a slight deviation from the normal Linux system * call behavior where scratch registers are preserved across * system calls (unless used by the system call itself). - * - * If we wanted to inherit the fph state from the parent to the - * child, we would have to do something along the lines of: - * - * if (ia64_get_fpu_owner() == current && ia64_psr(regs)->mfh) { - * p->thread.flags |= IA64_THREAD_FPH_VALID; - * ia64_save_fpu(&p->thread.fph); - * } else if (current->thread.flags & IA64_THREAD_FPH_VALID) { - * memcpy(p->thread.fph, current->thread.fph, sizeof(p->thread.fph)); - * } */ - p->thread.flags = (current->thread.flags & ~IA64_THREAD_FPH_VALID); +# define THREAD_FLAGS_TO_CLEAR (IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID) +# define THREAD_FLAGS_TO_SET 0 + p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR) + | THREAD_FLAGS_TO_SET); return 0; } @@ -537,17 +530,6 @@ if (ia64_get_fpu_owner() == current) { ia64_set_fpu_owner(0); } -} - -/* - * Free remaining state associated with DEAD_TASK. This is called - * after the parent of DEAD_TASK has collected the exist status of the - * task via wait(). - */ -void -release_thread (struct task_struct *dead_task) -{ - /* nothing to do */ } unsigned long diff -urN linux-2.4.0-test4/arch/ia64/kernel/ptrace.c linux-2.4.0-test4-lia/arch/ia64/kernel/ptrace.c --- linux-2.4.0-test4/arch/ia64/kernel/ptrace.c Fri Jun 23 21:11:20 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/ptrace.c Fri Jul 28 23:10:52 2000 @@ -549,6 +549,7 @@ ia64_sync_fph (struct task_struct *child) { if (ia64_psr(ia64_task_regs(child))->mfh && ia64_get_fpu_owner() == child) { + ia64_psr(ia64_task_regs(child))->mfh = 0; ia64_set_fpu_owner(0); ia64_save_fpu(&child->thread.fph[0]); child->thread.flags |= IA64_THREAD_FPH_VALID; @@ -942,9 +943,9 @@ ret = -EPERM; if (request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) + if (current->ptrace & PT_PTRACED) goto out; - current->flags |= PF_PTRACED; + current->ptrace |= PT_PTRACED; ret = 0; goto out; } @@ -976,9 +977,9 @@ (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out_tsk; /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) + if (child->ptrace & PT_PTRACED) goto out_tsk; - child->flags |= PF_PTRACED; + child->ptrace |= PT_PTRACED; if (child->p_pptr != current) { unsigned long flags; @@ -993,7 +994,7 @@ goto out_tsk; } ret = -ESRCH; - if (!(child->flags & PF_PTRACED)) + if (!(child->ptrace & PT_PTRACED)) goto out_tsk; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) @@ -1083,9 +1084,9 @@ if (data > _NSIG) goto out_tsk; if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; + child->ptrace |= PT_TRACESYS; else - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; /* make sure the single step/take-branch tra bits are not set: */ @@ -1126,7 +1127,7 @@ if (data > _NSIG) goto out_tsk; - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; if (request == PTRACE_SINGLESTEP) { ia64_psr(ia64_task_regs(child))->ss = 1; } else { @@ -1147,7 +1148,7 @@ if (data > _NSIG) goto out_tsk; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); child->exit_code = data; write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); @@ -1180,7 +1181,7 @@ void syscall_trace (void) { - if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) != (PT_PTRACED|PT_TRACESYS)) return; current->exit_code = SIGTRAP; set_current_state(TASK_STOPPED); diff -urN linux-2.4.0-test4/arch/ia64/kernel/setup.c linux-2.4.0-test4-lia/arch/ia64/kernel/setup.c --- linux-2.4.0-test4/arch/ia64/kernel/setup.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/setup.c Fri Jul 28 23:11:03 2000 @@ -122,6 +122,10 @@ */ memcpy(&ia64_boot_param, (void *) ZERO_PAGE_ADDR, sizeof(ia64_boot_param)); + *cmdline_p = __va(ia64_boot_param.command_line); + strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; /* for safety */ + efi_init(); max_pfn = 0; @@ -164,27 +168,21 @@ /* process SAL system table: */ ia64_sal_init(efi.sal_systab); - *cmdline_p = __va(ia64_boot_param.command_line); - strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; /* for safety */ - - printk("args to kernel: %s\n", *cmdline_p); - #ifdef CONFIG_SMP bootstrap_processor = hard_smp_processor_id(); current->processor = bootstrap_processor; #endif cpu_init(); /* initialize the bootstrap CPU */ +#ifdef CONFIG_IA64_GENERIC + machvec_init(acpi_get_sysname()); +#endif + if (efi.acpi) { /* Parse the ACPI tables */ acpi_parse(efi.acpi); } -#ifdef CONFIG_IA64_GENERIC - machvec_init(acpi_get_sysname()); -#endif - #ifdef CONFIG_VT # if defined(CONFIG_VGA_CONSOLE) conswitchp = &vga_con; @@ -197,8 +195,16 @@ /* enable IA-64 Machine Check Abort Handling */ ia64_mca_init(); #endif + paging_init(); platform_setup(cmdline_p); + +#ifdef CONFIG_SWIOTLB + { + extern void setup_swiotlb (void); + setup_swiotlb(); + } +#endif } /* @@ -241,18 +247,18 @@ sprintf(cp, " 0x%lx", mask); p += sprintf(p, - "CPU# %lu\n" - "\tvendor : %s\n" - "\tfamily : %s\n" - "\tmodel : %s\n" - "\trevision : %u\n" - "\tarchrev : %u\n" - "\tfeatures :%s\n" /* don't change this---it _is_ right! */ - "\tcpu number : %lu\n" - "\tcpu regs : %u\n" - "\tcpu MHz : %lu.%06lu\n" - "\titc MHz : %lu.%06lu\n" - "\tBogoMIPS : %lu.%02lu\n\n", + "processor : %lu\n" + "vendor : %s\n" + "family : %s\n" + "model : %s\n" + "revision : %u\n" + "archrev : %u\n" + "features :%s\n" /* don't change this---it _is_ right! */ + "cpu number : %lu\n" + "cpu regs : %u\n" + "cpu MHz : %lu.%06lu\n" + "itc MHz : %lu.%06lu\n" + "BogoMIPS : %lu.%02lu\n\n", c - cpu_data, c->vendor, family, model, c->revision, c->archrev, features, c->ppn, c->number, c->proc_freq / 1000000, c->proc_freq % 1000000, diff -urN linux-2.4.0-test4/arch/ia64/kernel/signal.c linux-2.4.0-test4-lia/arch/ia64/kernel/signal.c --- linux-2.4.0-test4/arch/ia64/kernel/signal.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/signal.c Thu Jul 13 15:54:09 2000 @@ -218,7 +218,7 @@ * be corrupted. */ retval = (long) &ia64_leave_kernel; - if (current->flags & PF_TRACESYS) + if (current->ptrace & PT_TRACESYS) /* * strace expects to be notified after sigreturn * returns even though the context to which we return @@ -492,7 +492,7 @@ if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; current->thread.siginfo = &info; @@ -570,7 +570,6 @@ /* FALLTHRU */ default: - lock_kernel(); sigaddset(¤t->signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; diff -urN linux-2.4.0-test4/arch/ia64/kernel/smp.c linux-2.4.0-test4-lia/arch/ia64/kernel/smp.c --- linux-2.4.0-test4/arch/ia64/kernel/smp.c Mon Jul 10 14:22:00 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/smp.c Fri Jul 28 23:11:44 2000 @@ -183,7 +183,7 @@ int wait; /* release the 'pointer lock' */ - data = smp_call_function_data; + data = (struct smp_call_struct *) smp_call_function_data; func = data->func; info = data->info; wait = data->wait; @@ -320,6 +320,58 @@ #endif /* !CONFIG_ITANIUM_PTCG */ /* + * Run a function on another CPU + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * If true, keep retrying until ready. + * If true, wait until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. + * + * Does not return until the remote CPU is nearly ready to execute + * or is or has executed. + */ + +int +smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int retry, int wait) +{ + struct smp_call_struct data; + long timeout; + int cpus = 1; + + if (cpuid == smp_processor_id()) { + printk(__FUNCTION__" trying to call self\n"); + return -EBUSY; + } + + data.func = func; + data.info = info; + data.wait = wait; + atomic_set(&data.unstarted_count, cpus); + atomic_set(&data.unfinished_count, cpus); + + if (pointer_lock(&smp_call_function_data, &data, retry)) + return -EBUSY; + + /* Send a message to all other CPUs and wait for them to respond */ + send_IPI_single(cpuid, IPI_CALL_FUNC); + + /* Wait for response */ + timeout = jiffies + HZ; + while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout)) + barrier(); + if (atomic_read(&data.unstarted_count) > 0) { + smp_call_function_data = NULL; + return -ETIMEDOUT; + } + if (wait) + while (atomic_read(&data.unfinished_count) > 0) + barrier(); + /* unlock pointer */ + smp_call_function_data = NULL; + return 0; +} + +/* * Run a function on all other CPUs. * The function to run. This must be fast and non-blocking. * An arbitrary pointer to pass to the function. @@ -498,6 +550,8 @@ extern void ia64_init_itm(void); extern void ia64_cpu_local_tick(void); + efi_map_pal_code(); + cpu_init(); smp_setup_percpu_timer(smp_processor_id()); @@ -536,7 +590,7 @@ * Don't care about the usp and regs settings since we'll never * reschedule the forked task. */ - return do_fork(CLONE_VM|CLONE_PID, 0, 0); + return do_fork(CLONE_VM|CLONE_PID, 0, 0, 0); } /* diff -urN linux-2.4.0-test4/arch/ia64/kernel/sys_ia64.c linux-2.4.0-test4-lia/arch/ia64/kernel/sys_ia64.c --- linux-2.4.0-test4/arch/ia64/kernel/sys_ia64.c Sat Jul 8 19:26:12 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/sys_ia64.c Thu Jul 13 15:54:09 2000 @@ -95,7 +95,6 @@ static inline unsigned long do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff) { - long start_low, end_low, starting_region, ending_region; unsigned long loff, hoff; struct file *file = 0; /* the virtual address space that is mappable in each region: */ @@ -109,17 +108,15 @@ return addr; /* Don't permit mappings into or across the address hole in a region: */ - loff = REGION_OFFSET(addr); - hoff = loff - (REGION_SIZE - OCTANT_SIZE/2); + loff = rgn_offset(addr); + hoff = loff - (RGN_SIZE - OCTANT_SIZE/2); if ((len | loff | (loff + len)) >= OCTANT_SIZE/2 && (len | hoff | (hoff + len)) >= OCTANT_SIZE/2) return -EINVAL; /* Don't permit mappings that would cross a region boundary: */ - starting_region = REGION_NUMBER(addr); - ending_region = REGION_NUMBER(addr + len); - if (starting_region != ending_region) + if (rgn_index(addr) != rgn_index(addr + len)) return -EINVAL; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); diff -urN linux-2.4.0-test4/arch/ia64/kernel/time.c linux-2.4.0-test4-lia/arch/ia64/kernel/time.c --- linux-2.4.0-test4/arch/ia64/kernel/time.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/time.c Fri Jul 28 23:12:00 2000 @@ -24,7 +24,7 @@ #include extern rwlock_t xtime_lock; -extern volatile unsigned long lost_ticks; +extern unsigned long wall_jiffies; #ifdef CONFIG_IA64_DEBUG_IRQ @@ -80,7 +80,7 @@ return 0; #else unsigned long now = ia64_get_itc(), last_tick; - unsigned long elapsed_cycles, lost = lost_ticks; + unsigned long elapsed_cycles, lost = jiffies - wall_jiffies; last_tick = (itm.next[smp_processor_id()].count - (lost+1)*itm.delta); # if 1 @@ -101,13 +101,15 @@ write_lock_irq(&xtime_lock); { /* - * This is revolting. We need to set the xtime.tv_usec + * This is revolting. We need to set "xtime" * correctly. However, the value in this location is - * is value at the last tick. Discover what - * correction gettimeofday would have done, and then - * undo it! + * the value at the most recent update of wall time. + * Discover what correction gettimeofday would have + * done, and then undo it! */ tv->tv_usec -= gettimeoffset(); + tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ); + while (tv->tv_usec < 0) { tv->tv_usec += 1000000; tv->tv_sec--; @@ -148,11 +150,13 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - static unsigned long last_time; - static unsigned char count; int cpu = smp_processor_id(); unsigned long new_itm; +#if 0 + static unsigned long last_time; + static unsigned char count; int printed = 0; +#endif /* * Here we are in the timer irq handler. We have irqs locally @@ -190,7 +194,7 @@ if (time_after(new_itm, ia64_get_itc())) break; -#if !(defined(CONFIG_IA64_SOFTSDV_HACKS) && defined(CONFIG_SMP)) +#if 0 /* * SoftSDV in SMP mode is _slow_, so we do "lose" ticks, * but it's really OK... diff -urN linux-2.4.0-test4/arch/ia64/kernel/traps.c linux-2.4.0-test4-lia/arch/ia64/kernel/traps.c --- linux-2.4.0-test4/arch/ia64/kernel/traps.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/traps.c Fri Jul 28 23:12:31 2000 @@ -204,11 +204,13 @@ { struct task_struct *fpu_owner = ia64_get_fpu_owner(); + /* first, clear psr.dfh and psr.mfh: */ regs->cr_ipsr &= ~(IA64_PSR_DFH | IA64_PSR_MFH); if (fpu_owner != current) { ia64_set_fpu_owner(current); if (fpu_owner && ia64_psr(ia64_task_regs(fpu_owner))->mfh) { + ia64_psr(ia64_task_regs(fpu_owner))->mfh = 0; fpu_owner->thread.flags |= IA64_THREAD_FPH_VALID; __ia64_save_fpu(fpu_owner->thread.fph); } @@ -216,6 +218,11 @@ __ia64_load_fpu(current->thread.fph); } else { __ia64_init_fpu(); + /* + * Set mfh because the state in thread.fph does not match + * the state in the fph partition. + */ + ia64_psr(regs)->mfh = 1; } } } diff -urN linux-2.4.0-test4/arch/ia64/kernel/unaligned.c linux-2.4.0-test4-lia/arch/ia64/kernel/unaligned.c --- linux-2.4.0-test4/arch/ia64/kernel/unaligned.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/unaligned.c Thu Jul 13 15:54:09 2000 @@ -1428,9 +1428,15 @@ if (unalign_count > 5 && jiffies - last_time > 5*HZ) unalign_count = 0; if (++unalign_count < 5) { + char buf[200]; /* comm[] is at most 16 bytes... */ + size_t len; + last_time = jiffies; - printk("%s(%d): unaligned trap accessing %016lx (ip=%016lx)\n", - current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); + len = sprintf(buf, "%s(%d): unaligned access to 0x%016lx, ip=0x%016lx\n\r", + current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); + tty_write_message(current->tty, buf); + buf[len-1] = '\0'; /* drop '\r' */ + printk("%s", buf); /* guard against command names containing %s!! */ } } diff -urN linux-2.4.0-test4/arch/ia64/kernel/unwind.c linux-2.4.0-test4-lia/arch/ia64/kernel/unwind.c --- linux-2.4.0-test4/arch/ia64/kernel/unwind.c Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/kernel/unwind.c Thu Jul 13 15:54:09 2000 @@ -66,9 +66,12 @@ #define UNW_STATS 0 /* WARNING: this disabled interrupts for long time-spans!! */ #if UNW_DEBUG + static long unw_debug_level = 1; +# define debug(level,format...) if (unw_debug_level > level) printk(format) # define dprintk(format...) printk(format) # define inline #else +# define debug(level,format...) # define dprintk(format...) #endif @@ -1600,11 +1603,10 @@ int have_write_lock = 0; struct unw_script *scr; - if ((info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) - || REGION_NUMBER(info->ip) != REGION_KERNEL) + if ((info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) || rgn_index(info->ip) != RGN_KERNEL) { /* don't let obviously bad addresses pollute the cache */ - dprintk("unwind: rejecting bad ip=0x%lx\n", info->ip); + debug(1, "unwind: rejecting bad ip=0x%lx\n", info->ip); info->rp = 0; return -1; } @@ -1647,7 +1649,7 @@ /* restore the ip */ if (!info->rp) { - dprintk("unwind: failed to locate return link (ip=0x%lx)!\n", info->ip); + debug(1, "unwind: failed to locate return link (ip=0x%lx)!\n", info->ip); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; } @@ -1657,7 +1659,7 @@ * We don't have unwind info for the gate page, so we consider that part * of user-space for the purpose of unwinding. */ - dprintk("unwind: reached user-space (ip=0x%lx)\n", ip); + debug(1, "unwind: reached user-space (ip=0x%lx)\n", ip); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; } diff -urN linux-2.4.0-test4/arch/ia64/lib/Makefile linux-2.4.0-test4-lia/arch/ia64/lib/Makefile --- linux-2.4.0-test4/arch/ia64/lib/Makefile Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/lib/Makefile Thu Jul 13 15:54:09 2000 @@ -7,40 +7,26 @@ L_TARGET = lib.a -L_OBJS = __divdi3.o __divsi3.o __udivdi3.o __udivsi3.o \ - __moddi3.o __modsi3.o __umoddi3.o __umodsi3.o \ - checksum.o clear_page.o csum_partial_copy.o copy_page.o \ - copy_user.o clear_user.o memset.o strncpy_from_user.o \ - strlen.o strlen_user.o strnlen_user.o \ +L_OBJS = __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o \ + checksum.o clear_page.o csum_partial_copy.o copy_page.o \ + copy_user.o clear_user.o memcpy.o memset.o strncpy_from_user.o \ + strlen.o strlen_user.o strnlen_user.o \ flush.o do_csum.o LX_OBJS = io.o -IGNORE_FLAGS_OBJS = __divdi3.o __divsi3.o __udivdi3.o __udivsi3.o \ - __moddi3.o __modsi3.o __umoddi3.o __umodsi3.o +IGNORE_FLAGS_OBJS = __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o include $(TOPDIR)/Rules.make __divdi3.o: idiv.S $(CC) $(AFLAGS) -c -o $@ $< -__divsi3.o: idiv.S - $(CC) $(AFLAGS) -c -DSINGLE -c -o $@ $< - __udivdi3.o: idiv.S $(CC) $(AFLAGS) -c -DUNSIGNED -c -o $@ $< -__udivsi3.o: idiv.S - $(CC) $(AFLAGS) -c -DUNSIGNED -DSINGLE -c -o $@ $< - __moddi3.o: idiv.S $(CC) $(AFLAGS) -c -DMODULO -c -o $@ $< -__modsi3.o: idiv.S - $(CC) $(AFLAGS) -c -DMODULO -DSINGLE -c -o $@ $< - __umoddi3.o: idiv.S $(CC) $(AFLAGS) -c -DMODULO -DUNSIGNED -c -o $@ $< - -__umodsi3.o: idiv.S - $(CC) $(AFLAGS) -c -DMODULO -DUNSIGNED -DSINGLE -c -o $@ $< diff -urN linux-2.4.0-test4/arch/ia64/lib/copy_user.S linux-2.4.0-test4-lia/arch/ia64/lib/copy_user.S --- linux-2.4.0-test4/arch/ia64/lib/copy_user.S Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/lib/copy_user.S Thu Jul 13 15:54:09 2000 @@ -116,7 +116,7 @@ cmp.lt p10,p7=COPY_BREAK,len // if len > COPY_BREAK then long copy xor tmp=src,dst // same alignment test prepare -(p10) br.cond.dptk.few long_memcpy +(p10) br.cond.dptk.few long_copy_user ;; // RAW pr.rot/p16 ? // // Now we do the byte by byte loop with software pipeline @@ -136,7 +136,7 @@ // // Beginning of long mempcy (i.e. > 16 bytes) // -long_memcpy: +long_copy_user: tbit.nz p6,p7=src1,0 // odd alignement and tmp=7,tmp ;; diff -urN linux-2.4.0-test4/arch/ia64/lib/idiv.S linux-2.4.0-test4-lia/arch/ia64/lib/idiv.S --- linux-2.4.0-test4/arch/ia64/lib/idiv.S Thu Jun 22 07:09:44 2000 +++ linux-2.4.0-test4-lia/arch/ia64/lib/idiv.S Thu Jul 13 15:54:09 2000 @@ -1,162 +1,98 @@ /* * Integer division routine. * - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 David Mosberger-Tang */ -/* Simple integer division. It uses the straight forward division - algorithm. This may not be the absolutely fastest way to do it, - but it's not horrible either. According to ski, the worst case - scenario of dividing 0xffffffffffffffff by 1 takes 133 cycles. - - An alternative would be to use an algorithm similar to the - floating point division algorithm (Newton-Raphson iteration), - but that approach is rather tricky (one has to be very careful - to get the last bit right...). - - While this algorithm is straight-forward, it does use a couple - of neat ia-64 specific tricks: - - - it uses the floating point unit to determine the initial - shift amount (shift = floor(ld(x)) - floor(ld(y))) - - - it uses predication to avoid a branch in the case where - x < y (this is what p8 is used for) - - - it uses rotating registers and the br.ctop branch to - implement a software-pipelined loop that's unrolled - twice (without any code expansion!) - - - the code is relatively well scheduled to avoid unnecessary - nops while maximizing parallelism -*/ #include -#include - .text - .psr abi64 -#ifdef __BIG_ENDIAN__ - .psr msb - .msb -#else - .psr lsb - .lsb -#endif +/* + * Compute a 64-bit unsigned integer quotient. + * + * Use reciprocal approximation and Newton-Raphson iteration to compute the + * quotient. frcpa gives 8.6 significant bits, so we need 3 iterations + * to get more than the 64 bits of precision that we need for DImode. + * + * Must use max precision for the reciprocal computations to get 64 bits of + * precision. + * + * r32 holds the dividend. r33 holds the divisor. + */ #ifdef MODULO # define OP mod -# define Q r9 -# define R r8 -#else -# define OP div -# define Q r8 -# define R r9 -#endif - -#ifdef SINGLE -# define PREC si #else -# define PREC di +# define OP div #endif #ifdef UNSIGNED -# define SGN u -# define INT_TO_FP(a,b) fma.s0 a=b,f1,f0 -# define FP_TO_INT(a,b) fcvt.fxu.trunc.s0 a=b +# define SGN u +# define INT_TO_FP(a,b) fcvt.xuf.s1 a=b +# define FP_TO_INT(a,b) fcvt.fxu.trunc.s1 a=b #else # define SGN # define INT_TO_FP(a,b) fcvt.xf a=b -# define FP_TO_INT(a,b) fcvt.fx.trunc.s0 a=b +# define FP_TO_INT(a,b) fcvt.fx.trunc.s1 a=b #endif #define PASTE1(a,b) a##b #define PASTE(a,b) PASTE1(a,b) -#define NAME PASTE(PASTE(__,SGN),PASTE(OP,PASTE(PREC,3))) +#define NAME PASTE(PASTE(__,SGN),PASTE(OP,di3)) GLOBAL_ENTRY(NAME) UNW(.prologue) - alloc r2=ar.pfs,2,6,0,8 - UNW(.save pr, r18) - mov r18=pr -#ifdef SINGLE -# ifdef UNSIGNED - zxt4 in0=in0 - zxt4 in1=in1 -# else - sxt4 in0=in0 - sxt4 in1=in1 -# endif - ;; -#endif + .regstk 2,0,0,0 + // Transfer inputs to FP registers. + setf.sig f8 = in0 + setf.sig f9 = in1 + UNW(.fframe 16) + UNW(.save.f 0x20) + stf.spill [sp] = f17,-16 -#ifndef UNSIGNED - cmp.lt p6,p0=in0,r0 // x negative? - cmp.lt p7,p0=in1,r0 // y negative? - ;; -(p6) sub in0=r0,in0 // make x positive -(p7) sub in1=r0,in1 // ditto for y + // Convert the inputs to FP, to avoid FP software-assist faults. + INT_TO_FP(f8, f8) ;; -#endif - - setf.sig f8=in0 - UNW(.save ar.lc, r3) + UNW(.save.f 0x10) + stf.spill [sp] = f16 UNW(.body) - - mov r3=ar.lc // save ar.lc - setf.sig f9=in1 + INT_TO_FP(f9, f9) + ;; + frcpa.s1 f17, p6 = f8, f9 // y = frcpa(b) + ;; + /* + * This is the magic algorithm described in Section 8.6.2 of "IA-64 + * and Elementary Functions" by Peter Markstein; HP Professional Books + * (http://www.hp.com/go/retailbooks/) + */ +(p6) fmpy.s1 f7 = f8, f17 // q = a*y +(p6) fnma.s1 f6 = f9, f17, f1 // e = -b*y + 1 + ;; +(p6) fma.s1 f16 = f7, f6, f7 // q1 = q*e + q +(p6) fmpy.s1 f7 = f6, f6 // e1 = e*e + ;; +(p6) fma.s1 f16 = f16, f7, f16 // q2 = q1*e1 + q1 +(p6) fma.s1 f6 = f17, f6, f17 // y1 = y*e + y + ;; +(p6) fma.s1 f6 = f6, f7, f6 // y2 = y1*e1 + y1 +(p6) fnma.s1 f7 = f9, f16, f8 // r = -b*q2 + a ;; - mov Q=0 // initialize q - mov R=in0 // stash away x in a static register - mov r16=1 // r16 = 1 - INT_TO_FP(f8,f8) - cmp.eq p8,p0=0,in0 // x==0? - cmp.eq p9,p0=0,in1 // y==0? - ;; - INT_TO_FP(f9,f9) -(p8) br.dpnt.few .L3 -(p9) break __IA64_BREAK_KDB // attempted division by zero (should never happen) - mov ar.ec=r0 // epilogue count = 0 - ;; - getf.exp r14=f8 // r14 = exponent of x - getf.exp r15=f9 // r15 = exponent of y - mov ar.lc=r0 // loop count = 0 - ;; - sub r17=r14,r15 // r17 = (exp of x - exp y) = shift amount - cmp.ge p8,p0=r14,r15 - ;; - - .rotr y[2], mask[2] // in0 and in1 may no longer be valid after - // the first write to a rotating register! - -(p8) shl y[1]=in1,r17 // y[1] = y<= y[1]) -(p8) shr.u mask[0]=mask[1],1 // prepare mask[0] and y[0] for next -(p8) shr.u y[0]=y[1],1 // iteration - ;; -(p9) sub R=R,y[1] // if (x >= y[1]), subtract y[1] from x -(p9) add Q=Q,mask[1] // and set corresponding bit in q (Q) - br.ctop.dptk.few .L1 // repeated unless ar.lc-- == 0 - ;; -.L2: -#ifndef UNSIGNED -# ifdef MODULO -(p6) sub R=r0,R // set sign of remainder according to x -# else -(p6) sub Q=r0,Q // set sign of quotient +(p6) fma.s1 f17 = f7, f6, f16 // q3 = r*y2 + q2 + ;; +#ifdef MODULO + FP_TO_INT(f17, f17) // round quotient to an unsigned integer + ;; + INT_TO_FP(f17, f17) // renormalize + ;; + fnma.s1 f17 = f17, f9, f8 // compute remainder ;; -(p7) sub Q=r0,Q -# endif #endif -.L3: - mov ar.pfs=r2 // restore ar.pfs - mov ar.lc=r3 // restore ar.lc - mov pr=r18,0xffffffffffff0000 // restore p16-p63 - br.ret.sptk.few rp + UNW(.restore sp) + ldf.fill f16 = [sp], 16 + FP_TO_INT(f8, f17) // round result to an (unsigned) integer + ;; + ldf.fill f17 = [sp] + getf.sig r8 = f8 // transfer result to result register + br.ret.sptk rp END(NAME) diff -urN linux-2.4.0-test4/arch/ia64/lib/memcpy.S linux-2.4.0-test4-lia/arch/ia64/lib/memcpy.S --- linux-2.4.0-test4/arch/ia64/lib/memcpy.S Wed Dec 31 16:00:00 1969 +++ linux-2.4.0-test4-lia/arch/ia64/lib/memcpy.S Thu Jul 13 15:54:09 2000 @@ -0,0 +1,86 @@ +#include + +GLOBAL_ENTRY(bcopy) + .regstk 3,0,0,0 + mov r8=in0 + mov in0=in1 + ;; + mov in1=r8 +END(bcopy) + // FALL THROUGH +GLOBAL_ENTRY(memcpy) + +# define MEM_LAT 4 + +# define N MEM_LAT-1 +# define Nrot ((MEM_LAT + 7) & ~7) + +# define dst r2 +# define src r3 +# define len r9 +# define saved_pfs r10 +# define saved_lc r11 +# define saved_pr r16 +# define t0 r17 +# define cnt r18 + + UNW(.prologue) + UNW(.save ar.pfs, saved_pfs) + alloc saved_pfs=ar.pfs,3,Nrot,0,Nrot + lfetch [in1] + + .rotr val[MEM_LAT] + .rotp p[MEM_LAT] + + UNW(.save ar.lc, saved_lc) + mov saved_lc=ar.lc + + or t0=in0,in1 + UNW(.save pr, saved_pr) + mov saved_pr=pr + + UNW(.body) + + mov ar.ec=MEM_LAT + + mov r8=in0 // return dst + shr cnt=in2,3 // number of 8-byte words to copy + mov pr.rot=1<<16 + ;; + cmp.eq p6,p0=in2,r0 // zero length? + or t0=t0,in2 +(p6) br.ret.spnt.many rp // yes, return immediately + + mov dst=in0 // copy because of rotation + mov src=in1 // copy because of rotation + adds cnt=-1,cnt // br.ctop is repeat/until + ;; + and t0=0x7,t0 + mov ar.lc=cnt + ;; + cmp.ne p6,p0=t0,r0 +(p6) br.cond.spnt.few slow_memcpy + +1: +(p[0]) ld8 val[0]=[src],8 +(p[N]) st8 [dst]=val[N],8 + br.ctop.sptk.few 1b + ;; +.exit: + mov ar.lc=saved_lc + mov pr=saved_pr,0xffffffffffff0000 + mov ar.pfs=saved_pfs + br.ret.sptk.many rp + +slow_memcpy: + adds cnt=-1,in2 + ;; + mov ar.lc=cnt + ;; +1: +(p[0]) ld1 val[0]=[src],1 +(p[N]) st1 [dst]=val[N],1 + br.ctop.sptk.few 1b + br.sptk.few .exit + +END(memcpy) diff -urN linux-2.4.0-test4/arch/ia64/mm/init.c linux-2.4.0-test4-lia/arch/ia64/mm/init.c --- linux-2.4.0-test4/arch/ia64/mm/init.c Thu Jun 22 07:09:45 2000 +++ linux-2.4.0-test4-lia/arch/ia64/mm/init.c Fri Jul 28 23:13:48 2000 @@ -423,5 +423,4 @@ #ifdef CONFIG_IA32_SUPPORT ia32_gdt_init(); #endif - return; } diff -urN linux-2.4.0-test4/arch/ia64/mm/tlb.c linux-2.4.0-test4-lia/arch/ia64/mm/tlb.c --- linux-2.4.0-test4/arch/ia64/mm/tlb.c Thu Jun 22 07:09:45 2000 +++ linux-2.4.0-test4-lia/arch/ia64/mm/tlb.c Thu Jul 13 15:54:09 2000 @@ -182,7 +182,7 @@ unsigned long nbits; if (mm != current->active_mm) { - /* this doesn't happen often, if at all, so it's not worth optimizing for... */ + /* this does happen, but perhaps it's not worth optimizing for? */ mm->context = 0; return; } diff -urN linux-2.4.0-test4/arch/ia64/sn/sn1/irq.c linux-2.4.0-test4-lia/arch/ia64/sn/sn1/irq.c --- linux-2.4.0-test4/arch/ia64/sn/sn1/irq.c Tue Feb 8 12:01:59 2000 +++ linux-2.4.0-test4-lia/arch/ia64/sn/sn1/irq.c Fri Jul 28 23:13:59 2000 @@ -1,9 +1,10 @@ #include +#include +#include -#include #include -static int +static unsigned int sn1_startup_irq(unsigned int irq) { return(0); @@ -24,23 +25,16 @@ { } -static int -sn1_handle_irq(unsigned int irq, struct pt_regs *regs) -{ - return(0); -} - struct hw_interrupt_type irq_type_sn1 = { "sn1_irq", sn1_startup_irq, sn1_shutdown_irq, - sn1_handle_irq, sn1_enable_irq, sn1_disable_irq }; void -sn1_irq_init (struct irq_desc desc[NR_IRQS]) +sn1_irq_init (void) { int i; diff -urN linux-2.4.0-test4/arch/ia64/sn/sn1/machvec.c linux-2.4.0-test4-lia/arch/ia64/sn/sn1/machvec.c --- linux-2.4.0-test4/arch/ia64/sn/sn1/machvec.c Sun Feb 6 18:42:40 2000 +++ linux-2.4.0-test4-lia/arch/ia64/sn/sn1/machvec.c Fri Jul 28 23:14:09 2000 @@ -1,4 +1,2 @@ +#define MACHVEC_PLATFORM_NAME sn1 #include -#include - -MACHVEC_DEFINE(sn1) diff -urN linux-2.4.0-test4/arch/ia64/sn/sn1/setup.c linux-2.4.0-test4-lia/arch/ia64/sn/sn1/setup.c --- linux-2.4.0-test4/arch/ia64/sn/sn1/setup.c Mon May 8 22:00:01 2000 +++ linux-2.4.0-test4-lia/arch/ia64/sn/sn1/setup.c Fri Jul 28 23:25:02 2000 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff -urN linux-2.4.0-test4/arch/ia64/tools/Makefile linux-2.4.0-test4-lia/arch/ia64/tools/Makefile --- linux-2.4.0-test4/arch/ia64/tools/Makefile Thu Jun 22 07:09:45 2000 +++ linux-2.4.0-test4-lia/arch/ia64/tools/Makefile Thu Jul 13 15:54:09 2000 @@ -11,10 +11,10 @@ fastdep: offsets.h @if ! cmp -s offsets.h ${TARGET}; then \ - echo "Updating ${TARGET}..."; \ + echo -e "*** Updating ${TARGET}..."; \ cp offsets.h ${TARGET}; \ else \ - echo "${TARGET} is up to date"; \ + echo "*** ${TARGET} is up to date"; \ fi # @@ -31,8 +31,10 @@ offsets.h: print_offsets ./print_offsets > offsets.h -print_offsets: print_offsets.c +print_offsets: print_offsets.c FORCE_RECOMPILE $(CC) $(CFLAGS) print_offsets.c -o $@ + +FORCE_RECOMPILE: else diff -urN linux-2.4.0-test4/arch/ia64/tools/print_offsets.awk linux-2.4.0-test4-lia/arch/ia64/tools/print_offsets.awk --- linux-2.4.0-test4/arch/ia64/tools/print_offsets.awk Sun Feb 6 18:42:40 2000 +++ linux-2.4.0-test4-lia/arch/ia64/tools/print_offsets.awk Thu Jul 13 15:54:09 2000 @@ -9,9 +9,10 @@ print " */" # # This is a cheesy hack. Make sure that - # PF_PTRACED == 1< so this seems - like a reasonably solution. At least the code won't break shoudl - PF_PTRACED ever change. */ - printf ("#define PF_PTRACED_BIT\t\t\t%u\n\n", ffs (PF_PTRACED) - 1); + for PT_PTRACED and it can't include so this seems + like a reasonably solution. At least the code won't break in + subtle ways should PT_PTRACED ever change. Ditto for + PT_TRACESYS_BIT. */ + printf ("#define PT_PTRACED_BIT\t\t\t%u\n", ffs (PT_PTRACED) - 1); + printf ("#define PT_TRACESYS_BIT\t\t\t%u\n\n", ffs (PT_TRACESYS) - 1); for (i = 0; i < sizeof (tab) / sizeof (tab[0]); ++i) { diff -urN linux-2.4.0-test4/arch/ia64/vmlinux.lds.S linux-2.4.0-test4-lia/arch/ia64/vmlinux.lds.S --- linux-2.4.0-test4/arch/ia64/vmlinux.lds.S Thu Jun 22 07:09:45 2000 +++ linux-2.4.0-test4-lia/arch/ia64/vmlinux.lds.S Fri Jul 28 23:15:14 2000 @@ -46,6 +46,15 @@ { *(__ex_table) } __stop___ex_table = .; +#if defined(CONFIG_IA64_GENERIC) + /* Machine Vector */ + . = ALIGN(16); + machvec_start = .; + .machvec : AT(ADDR(.machvec) - PAGE_OFFSET) + { *(.machvec) } + machvec_end = .; +#endif + __start___ksymtab = .; /* Kernel symbol table */ __ksymtab : AT(ADDR(__ksymtab) - PAGE_OFFSET) { *(__ksymtab) } @@ -125,6 +134,7 @@ /DISCARD/ : { *(.text.exit) *(.data.exit) + *(.exitcall.exit) } /* Stabs debugging sections. */ diff -urN linux-2.4.0-test4/drivers/char/Makefile linux-2.4.0-test4-lia/drivers/char/Makefile --- linux-2.4.0-test4/drivers/char/Makefile Mon Jun 26 11:57:49 2000 +++ linux-2.4.0-test4-lia/drivers/char/Makefile Thu Jul 13 15:54:09 2000 @@ -122,6 +122,7 @@ endif endif +obj-$(CONFIG_SIM_SERIAL) += simserial.o obj-$(CONFIG_ROCKETPORT) += rocket.o obj-$(CONFIG_MOXA_SMARTIO) += mxser.o obj-$(CONFIG_MOXA_INTELLIO) += moxa.o diff -urN linux-2.4.0-test4/drivers/char/efirtc.c linux-2.4.0-test4-lia/drivers/char/efirtc.c --- linux-2.4.0-test4/drivers/char/efirtc.c Tue Jun 20 07:32:13 2000 +++ linux-2.4.0-test4-lia/drivers/char/efirtc.c Thu Jul 13 15:54:09 2000 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff -urN linux-2.4.0-test4/drivers/char/simserial.c linux-2.4.0-test4-lia/drivers/char/simserial.c --- linux-2.4.0-test4/drivers/char/simserial.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.0-test4-lia/drivers/char/simserial.c Thu Jul 13 23:50:26 2000 @@ -0,0 +1,1094 @@ +/* + * Simulated Serial Driver (fake serial) + * + * This driver is mostly used for bringup purposes and will go away. + * It has a strong dependency on the system console. All outputs + * are rerouted to the same facility as the one used by printk which, in our + * case means sys_sim.c console (goes via the simulator). The code hereafter + * is completely leveraged from the serial.c driver. + * + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999 Stephane Eranian + * Copyright (C) 2000 David Mosberger-Tang + * + * 02/04/00 D. Mosberger Merged in serial.c bug fixes in rs_close(). + * 02/25/00 D. Mosberger Synced up with 2.3.99pre-5 version of serial.c. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#undef SIMSERIAL_DEBUG /* define this to get some debug information */ + +#define KEYBOARD_INTR 3 /* must match with simulator! */ +#define SIMSERIAL_IRQ 0xee + +#define NR_PORTS 1 /* only one port for now */ +#define SERIAL_INLINE 1 + +#ifdef SERIAL_INLINE +#define _INLINE_ inline +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) + +#define SSC_GETCHAR 21 + +extern long ia64_ssc (long, long, long, long, int); +extern void ia64_ssc_connect_irq (long intr, long irq); + +static char *serial_name = "SimSerial driver"; +static char *serial_version = "0.6"; + +/* + * This has been extracted from asm/serial.h. We need one eventually but + * I don't know exactly what we're going to put in it so just fake one + * for now. + */ +#define BASE_BAUD ( 1843200 / 16 ) + +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +/* + * Most of the values here are meaningless to this particular driver. + * However some values must be preserved for the code (leveraged from serial.c + * to work correctly). + * port must not be 0 + * type must not be UNKNOWN + * So I picked arbitrary (guess from where?) values instead + */ +static struct serial_state rs_table[NR_PORTS]={ + /* UART CLK PORT IRQ FLAGS */ + { 0, BASE_BAUD, 0x3F8, SIMSERIAL_IRQ, STD_COM_FLAGS,0,PORT_16550 } /* ttyS0 */ +}; + +/* + * Just for the fun of it ! + */ +static struct serial_uart_config uart_config[] = { + { "unknown", 1, 0 }, + { "8250", 1, 0 }, + { "16450", 1, 0 }, + { "16550", 1, 0 }, + { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, + { "cirrus", 1, 0 }, + { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, + { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, + { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, + { 0, 0} +}; + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +static struct async_struct *IRQ_ports[NR_IRQS]; +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +static struct console *console; + +static unsigned char *tmp_buf; +static DECLARE_MUTEX(tmp_buf_sem); + +extern struct console *console_drivers; /* from kernel/printk.c */ + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ +#ifdef SIMSERIAL_DEBUG + printk("rs_stop: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n", + tty->stopped, tty->hw_stopped, tty->flow_stopped); +#endif + +} + +static void rs_start(struct tty_struct *tty) +{ +#if SIMSERIAL_DEBUG + printk("rs_start: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n", + tty->stopped, tty->hw_stopped, tty->flow_stopped); +#endif +} + +static void receive_chars(struct tty_struct *tty) +{ + unsigned char ch; + static unsigned char seen_esc = 0; + + while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) { + if ( ch == 27 && seen_esc == 0 ) { + seen_esc = 1; + continue; + } else { + if ( seen_esc==1 && ch == 'O' ) { + seen_esc = 2; + continue; + } else if ( seen_esc == 2 ) { + if ( ch == 'P' ) show_state(); /* F1 key */ + if ( ch == 'Q' ) show_buffers(); /* F2 key */ + seen_esc = 0; + continue; + } + } + seen_esc = 0; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; + + *tty->flip.char_buf_ptr = ch; + + *tty->flip.flag_buf_ptr = 0; + + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + tty_flip_buffer_push(tty); +} + +/* + * This is the serial driver's interrupt routine for a single port + */ +static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) +{ + struct async_struct * info; + + /* + * I don't know exactly why they don't use the dev_id opaque data + * pointer instead of this extra lookup table + */ + info = IRQ_ports[irq]; + if (!info || !info->tty) { + printk("simrs_interrupt_single: info|tty=0 info=%p problem\n", info); + return; + } + /* + * pretty simple in our case, because we only get interrupts + * on inbound traffic + */ + receive_chars(info->tty); +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +#if 0 +/* + * not really used in our situation so keep them commented out for now + */ +static DECLARE_TASK_QUEUE(tq_serial); /* used to be at the top of the file */ +static void do_serial_bh(void) +{ + run_task_queue(&tq_serial); + printk("do_serial_bh: called\n"); +} +#endif + +static void do_softint(void *private_) +{ + printk("simserial: do_softint called\n"); +} + +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (!tty || !info->xmit.buf) return; + + save_flags(flags); cli(); + if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) { + restore_flags(flags); + return; + } + info->xmit.buf[info->xmit.head] = ch; + info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); + restore_flags(flags); +} + +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) +{ + int count; + unsigned long flags; + + save_flags(flags); cli(); + + if (info->x_char) { + char c = info->x_char; + + console->write(console, &c, 1); + + info->state->icount.tx++; + info->x_char = 0; + + goto out; + } + + if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) { +#ifdef SIMSERIAL_DEBUG + printk("transmit_chars: head=%d, tail=%d, stopped=%d\n", + info->xmit.head, info->xmit.tail, info->tty->stopped); +#endif + goto out; + } + /* + * We removed the loop and try to do it in to chunks. We need + * 2 operations maximum because it's a ring buffer. + * + * First from current to tail if possible. + * Then from the beginning of the buffer until necessary + */ + + count = MIN(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), + SERIAL_XMIT_SIZE - info->xmit.tail); + console->write(console, info->xmit.buf+info->xmit.tail, count); + + info->xmit.tail = (info->xmit.tail+count) & (SERIAL_XMIT_SIZE-1); + + /* + * We have more at the beginning of the buffer + */ + count = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + if (count) { + console->write(console, info->xmit.buf, count); + info->xmit.tail += count; + } +out: + restore_flags(flags); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped || + !info->xmit.buf) + return; + + transmit_chars(info, NULL); +} + + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (!tty || !info->xmit.buf || !tmp_buf) return 0; + + save_flags(flags); + if (from_user) { + down(&tmp_buf_sem); + while (1) { + int c1; + c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); + c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + if (c1 < c) + c = c1; + memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + cli(); + while (1) { + c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) { + break; + } + memcpy(info->xmit.buf + info->xmit.head, buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + buf += c; + count -= c; + ret += c; + } + restore_flags(flags); + } + /* + * Hey, we transmit directly from here in our case + */ + if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) + && !tty->stopped && !tty->hw_stopped) { + transmit_chars(info, NULL); + } + return ret; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + save_flags(flags); cli(); + info->xmit.head = info->xmit.tail = 0; + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void rs_send_xchar(struct tty_struct *tty, char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + info->x_char = ch; + if (ch) { + /* + * I guess we could call console->write() directly but + * let's do that for now. + */ + transmit_chars(info, NULL); + } +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); + + printk("simrs_throttle called\n"); +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_send_xchar(tty, START_CHAR(tty)); + } + printk("simrs_unthrottle called\n"); +} + +/* + * rs_break() --- routine which turns the break handling on or off + */ +static void rs_break(struct tty_struct *tty, int break_state) +{ +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + printk("rs_ioctl: TIOCMGET called\n"); + return -EINVAL; + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + printk("rs_ioctl: TIOCMBIS/BIC/SET called\n"); + return -EINVAL; + case TIOCGSERIAL: + printk("simrs_ioctl TIOCGSERIAL called\n"); + return 0; + case TIOCSSERIAL: + printk("simrs_ioctl TIOCSSERIAL called\n"); + return 0; + case TIOCSERCONFIG: + printk("rs_ioctl: TIOCSERCONFIG called\n"); + return -EINVAL; + + case TIOCSERGETLSR: /* Get line status register */ + printk("rs_ioctl: TIOCSERGETLSR called\n"); + return -EINVAL; + + case TIOCSERGSTRUCT: + printk("rs_ioctl: TIOCSERGSTRUCT called\n"); +#if 0 + if (copy_to_user((struct async_struct *) arg, + info, sizeof(struct async_struct))) + return -EFAULT; +#endif + return 0; + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + printk("rs_ioctl: TIOCMIWAIT: called\n"); + return 0; + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + printk("rs_ioctl: TIOCGICOUNT called\n"); + return 0; + + case TIOCSERGWILD: + case TIOCSERSWILD: + /* "setserial -W" is called in Debian boot */ + printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + unsigned int cflag = tty->termios->c_cflag; + + if ( (cflag == old_termios->c_cflag) + && ( RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } +} +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct async_struct * info) +{ + unsigned long flags; + struct serial_state *state; + int retval; + + if (!(info->flags & ASYNC_INITIALIZED)) return; + + state = info->state; + +#ifdef SIMSERIAL_DEBUG + printk("Shutting down serial port %d (irq %d)....", info->line, + state->irq); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, NULL); + retval = request_irq(state->irq, rs_interrupt_single, + IRQ_T(info), "serial", NULL); + + if (retval) + printk("serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, NULL); + } + + if (info->xmit.buf) { + free_page((unsigned long) info->xmit.buf); + info->xmit.buf = 0; + } + + if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state; + unsigned long flags; + + if (!info ) return; + + state = info->state; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { +#ifdef SIMSERIAL_DEBUG + printk("rs_close: hung_up\n"); +#endif + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } +#ifdef SIMSERIAL_DEBUG + printk("rs_close ttys%d, count = %d\n", info->line, state->count); +#endif + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + printk("rs_close: bad serial port count for ttys%d: %d\n", + info->line, state->count); + state->count = 0; + } + if (state->count) { + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + restore_flags(flags); + + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + shutdown(info); + if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + MOD_DEC_USE_COUNT; +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ +} + + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_hangup(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state = info->state; + +#ifdef SIMSERIAL_DEBUG + printk("rs_hangup: called\n"); +#endif + + state = info->state; + + rs_flush_buffer(tty); + if (info->flags & ASYNC_CLOSING) + return; + shutdown(info); + + info->event = 0; + state->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + + +static int get_async_struct(int line, struct async_struct **ret_info) +{ + struct async_struct *info; + struct serial_state *sstate; + + sstate = rs_table + line; + sstate->count++; + if (sstate->info) { + *ret_info = sstate->info; + return 0; + } + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); + if (!info) { + sstate->count--; + return -ENOMEM; + } + memset(info, 0, sizeof(struct async_struct)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + info->magic = SERIAL_MAGIC; + info->port = sstate->port; + info->flags = sstate->flags; + info->xmit_fifo_size = sstate->xmit_fifo_size; + info->line = line; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->state = sstate; + if (sstate->info) { + kfree_s(info, sizeof(struct async_struct)); + *ret_info = sstate->info; + return 0; + } + *ret_info = sstate->info = info; + return 0; +} + +static int +startup(struct async_struct *info) +{ + unsigned long flags; + int retval=0; + void (*handler)(int, void *, struct pt_regs *); + struct serial_state *state= info->state; + unsigned long page; + + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (!state->port || !state->type) { + if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + goto errout; + } + if (info->xmit.buf) + free_page(page); + else + info->xmit.buf = (unsigned char *) page; + +#ifdef SIMSERIAL_DEBUG + printk("startup: ttys%d (irq %d)...", info->line, state->irq); +#endif + + /* + * Allocate the IRQ if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + retval = -EBUSY; + goto errout; + } else + handler = rs_interrupt_single; + + retval = request_irq(state->irq, handler, IRQ_T(info), + "simserial", NULL); + if (retval) { + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, + &info->tty->flags); + retval = 0; + } + goto errout; + } + } + + /* + * Insert serial port into IRQ chain. + */ + info->prev_port = 0; + info->next_port = IRQ_ports[state->irq]; + if (info->next_port) + info->next_port->prev_port = info; + IRQ_ports[state->irq] = info; + + if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); + + info->xmit.head = info->xmit.tail = 0; + +#if 0 + /* + * Set up serial timers... + */ + timer_table[RS_TIMER].expires = jiffies + 2*HZ/100; + timer_active |= 1 << RS_TIMER; +#endif + + /* + * Set up the tty->alt_speed kludge + */ + if (info->tty) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + } + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; + +errout: + restore_flags(flags); + return retval; +} + + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct async_struct *info; + int retval, line; + unsigned long page; + + MOD_INC_USE_COUNT; + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) { + MOD_DEC_USE_COUNT; + return -ENODEV; + } + retval = get_async_struct(line, &info); + if (retval) { + MOD_DEC_USE_COUNT; + return retval; + } + tty->driver_data = info; + info->tty = tty; + +#ifdef SIMSERIAL_DEBUG + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->state->count); +#endif + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) { + /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ + return -ENOMEM; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); + /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) { + /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ + return retval; + } + + if ((info->state->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->state->normal_termios; + else + *tty->termios = info->state->callout_termios; + } + + /* + * figure out which console to use (should be one already) + */ + console = console_drivers; + while (console) { + if ((console->flags & CON_ENABLED) && console->write) break; + console = console->next; + } + + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SIMSERIAL_DEBUG + printk("rs_open ttys%d successful\n", info->line); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct serial_state *state) +{ + return sprintf(buf, "%d: uart:%s port:%lX irq:%d\n", + state->line, uart_config[state->type].name, + state->port, state->irq); +} + +int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0, l; + off_t begin = 0; + + len += sprintf(page, "simserinfo:1.0 driver:%s\n", serial_version); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + l = line_info(page + len, &rs_table[i]); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static inline void show_serial_version(void) +{ + printk(KERN_INFO "%s version %s with", serial_name, serial_version); + printk(" no serial options enabled\n"); +} + +/* + * The serial driver boot-time initialization code! + */ +static int __init +simrs_init (void) +{ + int i; + struct serial_state *state; + + show_serial_version(); + + /* connect the platform's keyboard interrupt to SIMSERIAL_IRQ */ + ia64_ssc_connect_irq(KEYBOARD_INTR, SIMSERIAL_IRQ); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "simserial"; + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64; + serial_driver.num = 1; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.put_char = rs_put_char; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.send_xchar = rs_send_xchar; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; + serial_driver.break_ctl = rs_break; + serial_driver.wait_until_sent = rs_wait_until_sent; + serial_driver.read_proc = rs_read_proc; + + /* + * Let's have a little bit of fun ! + */ + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + + if (state->type == PORT_UNKNOWN) continue; + + printk(KERN_INFO "ttyS%02d at 0x%04lx (irq = %d) is a %s\n", + state->line, + state->port, state->irq, + uart_config[state->type].name); + } + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; + + if (tty_register_driver(&serial_driver)) + panic("Couldn't register simserial driver\n"); + + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver\n"); + + return 0; +} + +#ifndef MODULE +__initcall(simrs_init); +#endif diff -urN linux-2.4.0-test4/drivers/net/Makefile linux-2.4.0-test4-lia/drivers/net/Makefile --- linux-2.4.0-test4/drivers/net/Makefile Mon Jun 19 13:30:57 2000 +++ linux-2.4.0-test4-lia/drivers/net/Makefile Thu Jul 13 15:54:09 2000 @@ -197,6 +197,7 @@ obj-$(CONFIG_ES3210) += es3210.o 8390.o obj-$(CONFIG_LNE390) += lne390.o 8390.o obj-$(CONFIG_NE3210) += ne3210.o 8390.o +obj-$(CONFIG_SIMETH) += simeth.o obj-$(CONFIG_PPP) += ppp_generic.o slhc.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o diff -urN linux-2.4.0-test4/drivers/net/eepro100.c linux-2.4.0-test4-lia/drivers/net/eepro100.c --- linux-2.4.0-test4/drivers/net/eepro100.c Tue Jul 11 11:12:23 2000 +++ linux-2.4.0-test4-lia/drivers/net/eepro100.c Fri Jul 28 23:15:43 2000 @@ -23,6 +23,8 @@ Convert to new PCI driver interface 2000 Mar 24 Dragan Stancevic Disabled FC and ER, to avoid lockups when when we get FCP interrupts. + 2000 Jul 17 Goutham Rao + PCI DMA API fixes, adding pci_dma_sync_single calls where neccesary */ static const char *version = @@ -39,9 +41,18 @@ static int txdmacount = 128; static int rxdmacount = 0; +#ifdef __ia64__ +/* + * Bug: this driver may generate unaligned accesses when not copying + * an incoming packet. Setting rx_copybreak to a large value force a + * copy and prevents unaligned accesses. + */ +static int rx_copybreak = 0x10000; +#else /* Set the copy breakpoint for the copy-only-tiny-buffer Rx method. Lower values use more memory, but are faster. */ static int rx_copybreak = 200; +#endif /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; @@ -427,14 +438,14 @@ /* The Speedo3 Rx and Tx frame/buffer descriptors. */ struct descriptor { /* A generic descriptor. */ - s32 cmd_status; /* All command and status fields. */ + volatile s32 cmd_status; /* All command and status fields. */ u32 link; /* struct descriptor * */ unsigned char params[0]; }; /* The Speedo3 Rx and Tx buffer descriptors. */ struct RxFD { /* Receive frame descriptor. */ - s32 status; + volatile s32 status; u32 link; /* struct RxFD * */ u32 rx_buf_addr; /* void * */ u32 count; @@ -515,6 +526,7 @@ spinlock_t lock; /* Group with Tx control cache line. */ u32 tx_threshold; /* The value for txdesc.count. */ struct RxFD *last_rxf; /* Last filled RX buffer. */ + dma_addr_t last_rxf_dma; unsigned int cur_rx, dirty_rx; /* The next free ring entry */ long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ const char *product_name; @@ -1210,19 +1222,24 @@ sp->rx_ring_dma[i] = pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); skb_reserve(skb, sizeof(struct RxFD)); - if (last_rxf) + if (last_rxf) { last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]); + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i-1], sizeof(struct RxFD), PCI_DMA_TODEVICE); + } last_rxf = rxf; rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */ rxf->link = 0; /* None yet. */ /* This field unused by i82557. */ rxf->rx_buf_addr = 0xffffffff; rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i], sizeof(struct RxFD), PCI_DMA_TODEVICE); } sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as end-of-list. */ last_rxf->status = cpu_to_le32(0xC0000002); /* '2' is flag value only. */ + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1], sizeof(struct RxFD), PCI_DMA_TODEVICE); sp->last_rxf = last_rxf; + sp->last_rxf_dma = sp->rx_ring_dma[RX_RING_SIZE-1]; } static void speedo_purge_tx(struct net_device *dev) @@ -1657,6 +1674,7 @@ skb->dev = dev; skb_reserve(skb, sizeof(struct RxFD)); rxf->rx_buf_addr = 0xffffffff; + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], sizeof(struct RxFD), PCI_DMA_TODEVICE); return rxf; } @@ -1669,7 +1687,9 @@ rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); sp->last_rxf->link = cpu_to_le32(rxf_dma); sp->last_rxf->status &= cpu_to_le32(~0xC0000000); + pci_dma_sync_single(sp->pdev, sp->last_rxf_dma, sizeof(struct RxFD), PCI_DMA_TODEVICE); sp->last_rxf = rxf; + sp->last_rxf_dma = rxf_dma; } static int speedo_refill_rx_buf(struct net_device *dev, int force) @@ -1735,9 +1755,17 @@ if (speedo_debug > 4) printk(KERN_DEBUG " In speedo_rx().\n"); /* If we own the next entry, it's a new packet. Send it up. */ - while (sp->rx_ringp[entry] != NULL && - (status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete) { - int pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; + while (sp->rx_ringp[entry] != NULL) { + int pkt_len; + + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); + + if(!((status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete)) { + break; + } + + pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; if (--rx_work_limit < 0) break; @@ -1779,7 +1807,8 @@ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], - PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); + sizeof(struct RxFD) + pkt_len, PCI_DMA_FROMDEVICE); + #if 1 || USE_IP_CSUM /* Packet is in one chunk -- we can copy + cksum. */ eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0); @@ -2162,6 +2191,8 @@ /* Set the link in the setup frame. */ mc_setup_frm->link = cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); + + pci_dma_sync_single(sp->pdev, mc_blk->frame_dma, mc_blk->len, PCI_DMA_TODEVICE); wait_for_cmd_done(ioaddr + SCBCmd); clear_suspend(last_cmd); diff -urN linux-2.4.0-test4/drivers/net/simeth.c linux-2.4.0-test4-lia/drivers/net/simeth.c --- linux-2.4.0-test4/drivers/net/simeth.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.0-test4-lia/drivers/net/simeth.c Thu Jul 13 15:54:09 2000 @@ -0,0 +1,600 @@ +/* + * Simulated Ethernet Driver + * + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 Stephane Eranain + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define SIMETH_IRQ 0xed +#define SIMETH_RECV_MAX 10 + +/* + * Maximum possible received frame for Ethernet. + * We preallocate an sk_buff of that size to avoid costly + * memcpy for temporary buffer into sk_buff. We do basically + * what's done in other drivers, like eepro with a ring. + * The difference is, of course, that we don't have real DMA !!! + */ +#define SIMETH_FRAME_SIZE ETH_FRAME_LEN + + +#define SSC_NETDEV_PROBE 100 +#define SSC_NETDEV_SEND 101 +#define SSC_NETDEV_RECV 102 +#define SSC_NETDEV_ATTACH 103 +#define SSC_NETDEV_DETACH 104 + +#define NETWORK_INTR 8 + +/* + * This structure is need for the module version + * It hasn't been tested yet + */ +struct simeth_local { + struct net_device *next_module; + struct net_device_stats stats; + int simfd; /* descriptor in the simulator */ +}; + +static int simeth_probe1(void); +static int simeth_open(struct net_device *dev); +static int simeth_close(struct net_device *dev); +static int simeth_tx(struct sk_buff *skb, struct net_device *dev); +static int simeth_rx(struct net_device *dev); +static struct net_device_stats *simeth_get_stats(struct net_device *dev); +static void simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static void set_multicast_list(struct net_device *dev); +static int simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr); + +static char *simeth_version="v0.2"; + +/* + * This variable is used to establish a mapping between the Linux/ia64 kernel + * and the host linux kernel. + * + * As of today, we support only one card, even though most of the code + * is ready for many more. The mapping is then: + * linux/ia64 -> linux/x86 + * eth0 -> eth1 + * + * In the future, we some string operations, we could easily support up + * to 10 cards (0-9). + * + * The default mapping can be changed on the kernel command line by + * specifying simeth=ethX (or whatever string you want). + */ +static char *simeth_device="eth0"; /* default host interface to use */ + + + +static volatile unsigned int card_count; /* how many cards "found" so far */ +static int simeth_debug=0; /* set to 1 to get debug information */ + +/* + * Used to catch IFF_UP & IFF_DOWN events + */ +static struct notifier_block simeth_dev_notifier = { + simeth_device_event, + 0 +}; + + +/* + * Function used when using a kernel command line option. + * + * Format: simeth=interface_name (like eth0) + */ +static int __init +simeth_setup(char *str) +{ + simeth_device = str; + return 1; +} + +__setup("simeth=", simeth_setup); + +/* + * Function used to probe for simeth devices when not installed + * as a loadable module + */ + +int __init +simeth_probe (void) +{ + return simeth_probe1(); +} + +extern long ia64_ssc (long, long, long, long, int); +extern void ia64_ssc_connect_irq (long intr, long irq); + +static inline int +netdev_probe(char *name, unsigned char *ether) +{ + return ia64_ssc(__pa(name), __pa(ether), 0,0, SSC_NETDEV_PROBE); +} + + +static inline int +netdev_connect(int irq) +{ + /* XXX Fix me + * this does not support multiple cards + * also no return value + */ + ia64_ssc_connect_irq(NETWORK_INTR, irq); + return 0; +} + +static inline int +netdev_attach(int fd, int irq, unsigned int ipaddr) +{ + /* this puts the host interface in the right mode (start interupting) */ + return ia64_ssc(fd, ipaddr, 0,0, SSC_NETDEV_ATTACH); +} + + +static inline int +netdev_detach(int fd) +{ + /* + * inactivate the host interface (don't interrupt anymore) */ + return ia64_ssc(fd, 0,0,0, SSC_NETDEV_DETACH); +} + +static inline int +netdev_send(int fd, unsigned char *buf, unsigned int len) +{ + return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_SEND); +} + +static inline int +netdev_read(int fd, unsigned char *buf, unsigned int len) +{ + return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_RECV); +} + +/* + * Function shared with module code, so cannot be in init section + * + * So far this function "detects" only one card (test_&_set) but could + * be extended easily. + * + * Return: + * - -ENODEV is no device found + * - -ENOMEM is no more memory + * - 0 otherwise + */ +static int +simeth_probe1(void) +{ + unsigned char mac_addr[ETH_ALEN]; + struct simeth_local *local; + struct net_device *dev; + int fd, i; + + /* + * XXX Fix me + * let's support just one card for now + */ + if (test_and_set_bit(0, &card_count)) + return -ENODEV; + + /* + * check with the simulator for the device + */ + fd = netdev_probe(simeth_device, mac_addr); + if (fd == -1) + return -ENODEV; + + dev = init_etherdev(NULL, sizeof(struct simeth_local)); + if (!dev) + return -ENOMEM; + + memcpy(dev->dev_addr, mac_addr, sizeof(mac_addr)); + /* + * XXX Fix me + * does not support more than one card ! + */ + dev->irq = SIMETH_IRQ; + + /* + * attach the interrupt in the simulator, this does enable interrupts + * until a netdev_attach() is called + */ + netdev_connect(dev->irq); + + memset(dev->priv, 0, sizeof(struct simeth_local)); + + local = dev->priv; + local->simfd = fd; /* keep track of underlying file descriptor */ + local->next_module = NULL; + + dev->open = simeth_open; + dev->stop = simeth_close; + dev->hard_start_xmit = simeth_tx; + dev->get_stats = simeth_get_stats; + dev->set_multicast_list = set_multicast_list; /* no yet used */ + + /* Fill in the fields of the device structure with ethernet-generic values. */ + ether_setup(dev); + + printk("simeth: %s alpha\n", simeth_version); + printk("%s: hosteth=%s simfd=%d, HwAddr", dev->name, simeth_device, local->simfd); + for(i = 0; i < ETH_ALEN; i++) { + printk(" %2.2x", dev->dev_addr[i]); + } + printk(", IRQ %d\n", dev->irq); + +#ifdef MODULE + local->next_module = simeth_dev; + simeth_dev = dev; +#endif + /* + * XXX Fix me + * would not work with more than one device ! + */ + register_netdevice_notifier(&simeth_dev_notifier); + + return 0; +} + +/* + * actually binds the device to an interrupt vector + */ +static int +simeth_open(struct net_device *dev) +{ + if (request_irq(dev->irq, simeth_interrupt, 0, "simeth", dev)) { + printk ("simeth: unable to get IRQ %d.\n", dev->irq); + return -EAGAIN; + } + + netif_start_queue(dev); + MOD_INC_USE_COUNT; + + return 0; +} + +/* copied from lapbether.c */ +static __inline__ int dev_is_ethdev(struct net_device *dev) +{ + return ( dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5)); +} + + +/* + * Handler for IFF_UP or IFF_DOWN + * + * The reason for that is that we don't want to be interrupted when the + * interface is down. There is no way to unconnect in the simualtor. Instead + * we use this function to shutdown packet processing in the frame filter + * in the simulator. Thus no interrupts are generated + * + * + * That's also the place where we pass the IP address of this device to the + * simulator so that that we can start filtering packets for it + * + * There may be a better way of doing this, but I don't know which yet. + */ +static int +simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) +{ + struct net_device *dev = (struct net_device *)ptr; + struct simeth_local *local; + struct in_device *in_dev; + struct in_ifaddr **ifap = NULL; + struct in_ifaddr *ifa = NULL; + int r; + + + if ( ! dev ) { + printk(KERN_WARNING "simeth_device_event dev=0\n"); + return NOTIFY_DONE; + } + + if ( event != NETDEV_UP && event != NETDEV_DOWN ) return NOTIFY_DONE; + + /* + * Check whether or not it's for an ethernet device + * + * XXX Fixme: This works only as long as we support one + * type of ethernet device. + */ + if ( !dev_is_ethdev(dev) ) return NOTIFY_DONE; + + if ((in_dev=dev->ip_ptr) != NULL) { + for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next) + if (strcmp(dev->name, ifa->ifa_label) == 0) break; + } + if ( ifa == NULL ) { + printk("simeth_open: can't find device %s's ifa\n", dev->name); + return NOTIFY_DONE; + } + + printk("simeth_device_event: %s ipaddr=0x%x\n", dev->name, htonl(ifa->ifa_local)); + + /* + * XXX Fix me + * if the device was up, and we're simply reconfiguring it, not sure + * we get DOWN then UP. + */ + + local = dev->priv; + /* now do it for real */ + r = event == NETDEV_UP ? + netdev_attach(local->simfd, dev->irq, htonl(ifa->ifa_local)): + netdev_detach(local->simfd); + + printk("simeth: netdev_attach/detach: event=%s ->%d\n", event == NETDEV_UP ? "attach":"detach", r); + + return NOTIFY_DONE; +} + +static int +simeth_close(struct net_device *dev) +{ + netif_stop_queue(dev); + + free_irq(dev->irq, dev); + + MOD_DEC_USE_COUNT; + + return 0; +} + +/* + * Only used for debug + */ +static void +frame_print(unsigned char *from, unsigned char *frame, int len) +{ + int i; + + printk("%s: (%d) %02x", from, len, frame[0] & 0xff); + for(i=1; i < 6; i++ ) { + printk(":%02x", frame[i] &0xff); + } + printk(" %2x", frame[6] &0xff); + for(i=7; i < 12; i++ ) { + printk(":%02x", frame[i] &0xff); + } + printk(" [%02x%02x]\n", frame[12], frame[13]); + + for(i=14; i < len; i++ ) { + printk("%02x ", frame[i] &0xff); + if ( (i%10)==0) printk("\n"); + } + printk("\n"); +} + + +/* + * Function used to transmit of frame, very last one on the path before + * going to the simulator. + */ +static int +simeth_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct simeth_local *local = (struct simeth_local *)dev->priv; + +#if 0 + /* ensure we have at least ETH_ZLEN bytes (min frame size) */ + unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + /* Where do the extra padding bytes comes from inthe skbuff ? */ +#else + /* the real driver in the host system is going to take care of that + * or maybe it's the NIC itself. + */ + unsigned int length = skb->len; +#endif + + local->stats.tx_bytes += skb->len; + local->stats.tx_packets++; + + + if (simeth_debug > 5) frame_print("simeth_tx", skb->data, length); + + netdev_send(local->simfd, skb->data, length); + + /* + * we are synchronous on write, so we don't simulate a + * trasnmit complete interrupt, thus we don't need to arm a tx + */ + + dev_kfree_skb(skb); + return 0; +} + +static inline struct sk_buff * +make_new_skb(struct net_device *dev) +{ + struct sk_buff *nskb; + + /* + * The +2 is used to make sure that the IP header is nicely + * aligned (on 4byte boundary I assume 14+2=16) + */ + nskb = dev_alloc_skb(SIMETH_FRAME_SIZE + 2); + if ( nskb == NULL ) { + printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name); + return NULL; + } + nskb->dev = dev; + + skb_reserve(nskb, 2); /* Align IP on 16 byte boundaries */ + + skb_put(nskb,SIMETH_FRAME_SIZE); + + return nskb; +} + +/* + * called from interrupt handler to process a received frame + */ +static int +simeth_rx(struct net_device *dev) +{ + struct simeth_local *local; + struct sk_buff *skb; + int len; + int rcv_count = SIMETH_RECV_MAX; + + local = (struct simeth_local *)dev->priv; + /* + * the loop concept has been borrowed from other drivers + * looks to me like it's a throttling thing to avoid pushing to many + * packets at one time into the stack. Making sure we can process them + * upstream and make forward progress overall + */ + do { + if ( (skb=make_new_skb(dev)) == NULL ) { + printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name); + local->stats.rx_dropped++; + return 0; + } + /* + * Read only one frame at a time + */ + len = netdev_read(local->simfd, skb->data, SIMETH_FRAME_SIZE); + if ( len == 0 ) { + if ( simeth_debug > 0 ) printk(KERN_WARNING "%s: count=%d netdev_read=0\n", dev->name, SIMETH_RECV_MAX-rcv_count); + break; + } +#if 0 + /* + * XXX Fix me + * Should really do a csum+copy here + */ + memcpy(skb->data, frame, len); +#endif + skb->protocol = eth_type_trans(skb, dev); + + if ( simeth_debug > 6 ) frame_print("simeth_rx", skb->data, len); + + /* + * push the packet up & trigger software interrupt + */ + netif_rx(skb); + + local->stats.rx_packets++; + local->stats.rx_bytes += len; + + } while ( --rcv_count ); + + return len; /* 0 = nothing left to read, otherwise, we can try again */ +} + +/* + * Interrupt handler (Yes, we can do it too !!!) + */ +static void +simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + + if ( dev == NULL ) { + printk(KERN_WARNING "simeth: irq %d for unknown device\n", irq); + return; + } + + /* + * very simple loop because we get interrupts only when receving + */ + while (simeth_rx(dev)); +} + +static struct net_device_stats * +simeth_get_stats(struct net_device *dev) +{ + struct simeth_local *local = (struct simeth_local *) dev->priv; + + return &local->stats; +} + +/* fake multicast ability */ +static void +set_multicast_list(struct net_device *dev) +{ + printk(KERN_WARNING "%s: set_multicast_list called\n", dev->name); +} + +#ifdef CONFIG_NET_FASTROUTE +static int +simeth_accept_fastpath(struct net_device *dev, struct dst_entry *dst) +{ + printk(KERN_WARNING "%s: simeth_accept_fastpath called\n", dev->name); + return -1; +} +#endif + + +#ifdef MODULE +static int +simeth_init(void) +{ + unsigned int cards_found = 0; + + /* iterate over probe */ + + while ( simeth_probe1() == 0 ) cards_found++; + + return cards_found ? 0 : -ENODEV; +} + + +int +init_module(void) +{ + simeth_dev = NULL; + + /* the register_netdev is done "indirectly by ether_initdev() */ + + return simeth_init(); +} + +void +cleanup_module(void) +{ + struct net_device *next; + + while ( simeth_dev ) { + + next = ((struct simeth_private *)simeth_dev->priv)->next_module; + + unregister_netdev(simeth_dev); + + kfree(simeth_dev); + + simeth_dev = next; + } + /* + * XXX fix me + * not clean wihen multiple devices + */ + unregister_netdevice_notifier(&simeth_dev_notifier); +} +#else /* !MODULE */ +__initcall(simeth_probe); +#endif /* !MODULE */ diff -urN linux-2.4.0-test4/drivers/scsi/Makefile linux-2.4.0-test4-lia/drivers/scsi/Makefile --- linux-2.4.0-test4/drivers/scsi/Makefile Tue Jun 20 14:14:51 2000 +++ linux-2.4.0-test4-lia/drivers/scsi/Makefile Thu Jul 13 15:54:09 2000 @@ -41,6 +41,7 @@ obj-$(CONFIG_SCSI_PSI240I) += psi240i.o obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o +obj-$(CONFIG_SCSI_SIM) += simscsi.o obj-$(CONFIG_SCSI_SIM710) += sim710.o obj-$(CONFIG_A4000T_SCSI) += amiga7xx.o 53c7xx.o obj-$(CONFIG_A4091_SCSI) += amiga7xx.o 53c7xx.o diff -urN linux-2.4.0-test4/drivers/scsi/hosts.c linux-2.4.0-test4-lia/drivers/scsi/hosts.c --- linux-2.4.0-test4/drivers/scsi/hosts.c Tue Jul 11 11:17:45 2000 +++ linux-2.4.0-test4-lia/drivers/scsi/hosts.c Thu Jul 13 15:54:09 2000 @@ -325,6 +325,10 @@ #include "scsi_debug.h" #endif +#ifdef CONFIG_SCSI_SIM +#include "simscsi.h" +#endif + #ifdef CONFIG_SCSI_ACORNSCSI_3 #include "../acorn/scsi/acornscsi.h" #endif @@ -637,6 +641,9 @@ #endif #ifdef CONFIG_SCSI_PLUTO PLUTO, +#endif +#ifdef CONFIG_SCSI_SIM + SIMSCSI, #endif #ifdef CONFIG_ARCH_ACORN #ifdef CONFIG_SCSI_ACORNSCSI_3 diff -urN linux-2.4.0-test4/drivers/scsi/qla1280.c linux-2.4.0-test4-lia/drivers/scsi/qla1280.c --- linux-2.4.0-test4/drivers/scsi/qla1280.c Mon Jun 19 13:42:40 2000 +++ linux-2.4.0-test4-lia/drivers/scsi/qla1280.c Fri Jul 28 23:15:55 2000 @@ -809,6 +809,7 @@ index++, &pci_bus, &pci_devfn)) ) { #endif /* found a adapter */ + template->unchecked_isa_dma = 1; host = scsi_register(template, sizeof(scsi_qla_host_t)); ha = (scsi_qla_host_t *) host->hostdata; /* Clear our data area */ diff -urN linux-2.4.0-test4/drivers/scsi/simscsi.c linux-2.4.0-test4-lia/drivers/scsi/simscsi.c --- linux-2.4.0-test4/drivers/scsi/simscsi.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.0-test4-lia/drivers/scsi/simscsi.c Thu Jul 13 15:54:09 2000 @@ -0,0 +1,359 @@ +/* + * Simulated SCSI driver. + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999 Stephane Eranian + * + * 99/12/18 David Mosberger Added support for READ10/WRITE10 needed by linux v2.3.33 + */ +#include +#include +#include +#include +#include + +#include + +#include + +#include "scsi.h" +#include "sd.h" +#include "hosts.h" +#include "simscsi.h" + +#define DEBUG_SIMSCSI 0 + +/* Simulator system calls: */ + +#define SSC_OPEN 50 +#define SSC_CLOSE 51 +#define SSC_READ 52 +#define SSC_WRITE 53 +#define SSC_GET_COMPLETION 54 +#define SSC_WAIT_COMPLETION 55 + +#define SSC_WRITE_ACCESS 2 +#define SSC_READ_ACCESS 1 + +struct timer_list disk_timer; + +struct disk_req { + unsigned long addr; + unsigned len; +}; + +struct disk_stat { + int fd; + unsigned count; +}; + +extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr); + +static int desc[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; + +static struct queue_entry { + Scsi_Cmnd *sc; +} queue[SIMSCSI_REQ_QUEUE_LEN]; + +static int rd, wr; +static atomic_t num_reqs = ATOMIC_INIT(0); + +/* base name for default disks */ +static char *simscsi_root = DEFAULT_SIMSCSI_ROOT; + +#define MAX_ROOT_LEN 128 + +/* + * used to setup a new base for disk images + * to use /foo/bar/disk[a-z] as disk images + * you have to specify simscsi=/foo/bar/disk on the command line + */ +static int __init +simscsi_setup (char *s) +{ + /* XXX Fix me we may need to strcpy() ? */ + if (strlen(s) > MAX_ROOT_LEN) { + printk("simscsi_setup: prefix too long---using default %s\n", simscsi_root); + } + simscsi_root = s; + return 1; +} + +__setup("simscsi=", simscsi_setup); + +static void +simscsi_interrupt (unsigned long val) +{ + unsigned long flags; + Scsi_Cmnd *sc; + + spin_lock_irqsave(&io_request_lock, flags); + { + while ((sc = queue[rd].sc) != 0) { + atomic_dec(&num_reqs); + queue[rd].sc = 0; +#if DEBUG_SIMSCSI + printk("simscsi_interrupt: done with %ld\n", sc->serial_number); +#endif + (*sc->scsi_done)(sc); + rd = (rd + 1) % SIMSCSI_REQ_QUEUE_LEN; + } + } + spin_unlock_irqrestore(&io_request_lock, flags); +} + +int +simscsi_detect (Scsi_Host_Template *templ) +{ + templ->proc_name = "simscsi"; + init_timer(&disk_timer); + disk_timer.function = simscsi_interrupt; + return 1; /* fake one SCSI host adapter */ +} + +int +simscsi_release (struct Scsi_Host *host) +{ + return 0; /* this is easy... */ +} + +const char * +simscsi_info (struct Scsi_Host *host) +{ + return "simulated SCSI host adapter"; +} + +int +simscsi_abort (Scsi_Cmnd *cmd) +{ + printk ("simscsi_abort: unimplemented\n"); + return SCSI_ABORT_SUCCESS; +} + +int +simscsi_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) +{ + printk ("simscsi_reset: unimplemented\n"); + return SCSI_RESET_SUCCESS; +} + +int +simscsi_biosparam (Disk *disk, kdev_t n, int ip[]) +{ + int size = disk->capacity; + + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + return 0; +} + +static void +simscsi_readwrite (Scsi_Cmnd *sc, int mode, unsigned long offset, unsigned long len) +{ + struct disk_stat stat; + struct disk_req req; + + req.addr = __pa(sc->request_buffer); + req.len = len; /* # of bytes to transfer */ + + if (sc->request_bufflen < req.len) + return; + + stat.fd = desc[sc->target]; +#if DEBUG_SIMSCSI + printk("simscsi_%s @ %lx (off %lx)\n", + mode == SSC_READ ? "read":"write", req.addr, offset); +#endif + ia64_ssc(stat.fd, 1, __pa(&req), offset, mode); + ia64_ssc(__pa(&stat), 0, 0, 0, SSC_WAIT_COMPLETION); + + if (stat.count == req.len) { + sc->result = GOOD; + } else { + sc->result = DID_ERROR << 16; + } +} + +static void +simscsi_sg_readwrite (Scsi_Cmnd *sc, int mode, unsigned long offset) +{ + int list_len = sc->use_sg; + struct scatterlist *sl = (struct scatterlist *)sc->buffer; + struct disk_stat stat; + struct disk_req req; + + stat.fd = desc[sc->target]; + + while (list_len) { + req.addr = __pa(sl->address); + req.len = sl->length; +#if DEBUG_SIMSCSI + printk("simscsi_sg_%s @ %lx (off %lx) use_sg=%d len=%d\n", + mode == SSC_READ ? "read":"write", req.addr, offset, list_len, sl->length); +#endif + ia64_ssc(stat.fd, 1, __pa(&req), offset, mode); + ia64_ssc(__pa(&stat), 0, 0, 0, SSC_WAIT_COMPLETION); + + /* should not happen in our case */ + if (stat.count != req.len) { + sc->result = DID_ERROR << 16; + return; + } + offset += sl->length; + sl++; + list_len--; + } + sc->result = GOOD; +} + +/* + * function handling both READ_6/WRITE_6 (non-scatter/gather mode) + * commands. + * Added 02/26/99 S.Eranian + */ +static void +simscsi_readwrite6 (Scsi_Cmnd *sc, int mode) +{ + unsigned long offset; + + offset = (((sc->cmnd[1] & 0x1f) << 16) | (sc->cmnd[2] << 8) | sc->cmnd[3])*512; + if (sc->use_sg > 0) + simscsi_sg_readwrite(sc, mode, offset); + else + simscsi_readwrite(sc, mode, offset, sc->cmnd[4]*512); +} + + +static void +simscsi_readwrite10 (Scsi_Cmnd *sc, int mode) +{ + unsigned long offset; + + offset = ( (sc->cmnd[2] << 24) | (sc->cmnd[3] << 16) + | (sc->cmnd[4] << 8) | (sc->cmnd[5] << 0))*512; + if (sc->use_sg > 0) + simscsi_sg_readwrite(sc, mode, offset); + else + simscsi_readwrite(sc, mode, offset, ((sc->cmnd[7] << 8) | sc->cmnd[8])*512); +} + +int +simscsi_queuecommand (Scsi_Cmnd *sc, void (*done)(Scsi_Cmnd *)) +{ + char fname[MAX_ROOT_LEN+16]; + char *buf; + +#if DEBUG_SIMSCSI + register long sp asm ("sp"); + printk("simscsi_queuecommand: target=%d,cmnd=%u,sc=%lu,sp=%lx,done=%p\n", + sc->target, sc->cmnd[0], sc->serial_number, sp, done); +#endif + + sc->result = DID_BAD_TARGET << 16; + sc->scsi_done = done; + if (sc->target <= 7 && sc->lun == 0) { + switch (sc->cmnd[0]) { + case INQUIRY: + if (sc->request_bufflen < 35) { + break; + } + sprintf (fname, "%s%c", simscsi_root, 'a' + sc->target); + desc[sc->target] = ia64_ssc (__pa(fname), SSC_READ_ACCESS|SSC_WRITE_ACCESS, + 0, 0, SSC_OPEN); + if (desc[sc->target] < 0) { + /* disk doesn't exist... */ + break; + } + buf = sc->request_buffer; + buf[0] = 0; /* magnetic disk */ + buf[1] = 0; /* not a removable medium */ + buf[2] = 2; /* SCSI-2 compliant device */ + buf[3] = 2; /* SCSI-2 response data format */ + buf[4] = 31; /* additional length (bytes) */ + buf[5] = 0; /* reserved */ + buf[6] = 0; /* reserved */ + buf[7] = 0; /* various flags */ + memcpy(buf + 8, "HP SIMULATED DISK 0.00", 28); + sc->result = GOOD; + break; + + case TEST_UNIT_READY: + sc->result = GOOD; + break; + + case READ_6: + if (desc[sc->target] < 0 ) + break; + simscsi_readwrite6(sc, SSC_READ); + break; + + case READ_10: + if (desc[sc->target] < 0 ) + break; + simscsi_readwrite10(sc, SSC_READ); + break; + + case WRITE_6: + if (desc[sc->target] < 0) + break; + simscsi_readwrite6(sc, SSC_WRITE); + break; + + case WRITE_10: + if (desc[sc->target] < 0) + break; + simscsi_readwrite10(sc, SSC_WRITE); + break; + + + case READ_CAPACITY: + if (desc[sc->target] < 0 || sc->request_bufflen < 8) { + break; + } + buf = sc->request_buffer; + + /* pretend to be a 1GB disk (partition table contains real stuff): */ + buf[0] = 0x00; + buf[1] = 0x1f; + buf[2] = 0xff; + buf[3] = 0xff; + /* set block size of 512 bytes: */ + buf[4] = 0; + buf[5] = 0; + buf[6] = 2; + buf[7] = 0; + sc->result = GOOD; + break; + + case MODE_SENSE: + printk("MODE_SENSE\n"); + break; + + case START_STOP: + printk("START_STOP\n"); + break; + + default: + panic("simscsi: unknown SCSI command %u\n", sc->cmnd[0]); + } + } + if (sc->result == DID_BAD_TARGET) { + sc->result |= DRIVER_SENSE << 24; + sc->sense_buffer[0] = 0x70; + sc->sense_buffer[2] = 0x00; + } + if (atomic_read(&num_reqs) >= SIMSCSI_REQ_QUEUE_LEN) { + panic("Attempt to queue command while command is pending!!"); + } + atomic_inc(&num_reqs); + queue[wr].sc = sc; + wr = (wr + 1) % SIMSCSI_REQ_QUEUE_LEN; + + if (!timer_pending(&disk_timer)) { + disk_timer.expires = jiffies + HZ/20; + add_timer(&disk_timer); + } + return 0; +} diff -urN linux-2.4.0-test4/drivers/scsi/simscsi.h linux-2.4.0-test4-lia/drivers/scsi/simscsi.h --- linux-2.4.0-test4/drivers/scsi/simscsi.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.0-test4-lia/drivers/scsi/simscsi.h Thu Jul 13 15:54:09 2000 @@ -0,0 +1,39 @@ +/* + * Simulated SCSI driver. + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + */ +#ifndef SIMSCSI_H +#define SIMSCSI_H + +#define SIMSCSI_REQ_QUEUE_LEN 64 + +#define DEFAULT_SIMSCSI_ROOT "/var/ski-disks/sd" + +extern int simscsi_detect (Scsi_Host_Template *); +extern int simscsi_release (struct Scsi_Host *); +extern const char *simscsi_info (struct Scsi_Host *); +extern int simscsi_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int simscsi_abort (Scsi_Cmnd *); +extern int simscsi_reset (Scsi_Cmnd *, unsigned int); +extern int simscsi_biosparam (Disk *, kdev_t, int[]); + +#define SIMSCSI { \ + detect: simscsi_detect, \ + release: simscsi_release, \ + info: simscsi_info, \ + queuecommand: simscsi_queuecommand, \ + abort: simscsi_abort, \ + reset: simscsi_reset, \ + bios_param: simscsi_biosparam, \ + can_queue: SIMSCSI_REQ_QUEUE_LEN, \ + this_id: -1, \ + sg_tablesize: 32, \ + cmd_per_lun: SIMSCSI_REQ_QUEUE_LEN, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING \ +} + +#endif /* SIMSCSI_H */ diff -urN linux-2.4.0-test4/drivers/usb/uhci.c linux-2.4.0-test4-lia/drivers/usb/uhci.c --- linux-2.4.0-test4/drivers/usb/uhci.c Sat May 20 11:39:27 2000 +++ linux-2.4.0-test4-lia/drivers/usb/uhci.c Thu Jul 13 15:54:09 2000 @@ -33,7 +33,7 @@ #include #include #include -#define DEBUG +#undef DEBUG #include #include @@ -67,6 +67,46 @@ /* If a transfer is still active after this much time, turn off FSBR */ #define IDLE_TIMEOUT (HZ / 20) /* 50 ms */ +#ifdef CONFIG_ITANIUM_A1_SPECIFIC + +static struct uhci *guhci; + +void +disable_usb (void) +{ + unsigned short cmd; + unsigned int io_addr; + + if (guhci == NULL) + return; + + io_addr = guhci->io_addr; + + cmd = inw (io_addr + USBCMD); + + outw(cmd & ~ USBCMD_RS, io_addr+USBCMD); + + while ((inw (io_addr + USBSTS) & USBSTS_HCH) == 0); +} + +void +reenable_usb (void) +{ + unsigned int io_addr; + unsigned short cmd; + + if (guhci == NULL) + return; + + io_addr = guhci->io_addr; + + cmd = inw (io_addr + USBCMD); + + outw(cmd | USBCMD_RS, io_addr+USBCMD); +} + +#endif /* CONFIG_ITANIUM_A1_SPECIFIC */ + /* * Only the USB core should call uhci_alloc_dev and uhci_free_dev */ @@ -2303,6 +2343,11 @@ if (!uhci_start_root_hub(uhci)) { struct pm_dev *pmdev; +#ifdef CONFIG_ITANIUM_A1_SPECIFIC + guhci = uhci; + printk("%s: enabling Lion USB workaround io_addr=%x\n", + __FILE__, guhci->io_addr); +#endif pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(dev), handle_pm_event); diff -urN linux-2.4.0-test4/fs/binfmt_elf.c linux-2.4.0-test4-lia/fs/binfmt_elf.c --- linux-2.4.0-test4/fs/binfmt_elf.c Tue Jul 11 15:43:45 2000 +++ linux-2.4.0-test4-lia/fs/binfmt_elf.c Thu Jul 13 15:54:09 2000 @@ -41,6 +41,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_elf_library(struct file*); +static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); extern void dump_thread(struct pt_regs *, struct user *); @@ -59,9 +60,15 @@ #define elf_core_dump NULL #endif -#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1)) -#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1)) -#define ELF_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1)) +#if ELF_EXEC_PAGESIZE > PAGE_SIZE +# define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE +#else +# define ELF_MIN_ALIGN PAGE_SIZE +#endif + +#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1)) +#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1)) +#define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) static struct linux_binfmt elf_format = { NULL, THIS_MODULE, load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE @@ -89,7 +96,7 @@ nbyte = ELF_PAGEOFFSET(elf_bss); if (nbyte) { - nbyte = ELF_EXEC_PAGESIZE - nbyte; + nbyte = ELF_MIN_ALIGN - nbyte; clear_user((void *) elf_bss, nbyte); } } @@ -198,6 +205,22 @@ return sp; } +#ifndef elf_map + +static inline unsigned long +elf_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) +{ + unsigned long map_addr; + + down(¤t->mm->mmap_sem); + map_addr = do_mmap(filep, ELF_PAGESTART(addr), + eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type, + eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); + up(¤t->mm->mmap_sem); + return(map_addr); +} + +#endif /* !elf_map */ /* This is much more generalized than the library routine read function, so we keep this separate. Technically the library read function @@ -235,7 +258,7 @@ /* Now read in all of the header information */ size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum; - if (size > ELF_EXEC_PAGESIZE) + if (size > ELF_MIN_ALIGN) goto out; elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL); if (!elf_phdata) @@ -261,16 +284,7 @@ if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) elf_type |= MAP_FIXED; - down(¤t->mm->mmap_sem); - map_addr = do_mmap(interpreter, - load_addr + ELF_PAGESTART(vaddr), - eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), - elf_prot, - elf_type, - eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); - up(¤t->mm->mmap_sem); - if (map_addr > -1024UL) /* Real error */ - goto out_close; + map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type); if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { load_addr = map_addr - ELF_PAGESTART(vaddr); @@ -304,7 +318,7 @@ * last bss page. */ padzero(elf_bss); - elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */ + elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); /* What we have mapped so far */ /* Map the last of the bss segment */ if (last_bss > elf_bss) @@ -356,7 +370,7 @@ flush_icache_range((unsigned long)addr, (unsigned long)addr + text_data); - do_brk(ELF_PAGESTART(text_data + ELF_EXEC_PAGESIZE - 1), + do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1), interp_ex->a_bss); elf_entry = interp_ex->a_entry; @@ -468,6 +482,20 @@ if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) ibcs2_interpreter = 1; +#if defined(__ia64__) && !defined(CONFIG_BINFMT_ELF32) + /* + * XXX temporary gross hack until all IA-64 Linux binaries + * use /lib/ld-linux-ia64.so.1 as the linker name. + */ +#define INTRP64 "/lib/ld-linux-ia64.so.1" + if (strcmp(elf_interpreter,"/lib/ld-linux.so.2") == 0) { + kfree(elf_interpreter); + elf_interpreter=(char *)kmalloc(sizeof(INTRP64), GFP_KERNEL); + if (!elf_interpreter) + goto out_free_file; + strcpy(elf_interpreter, INTRP64); + } +#endif /* defined(__ia64__) && !defined(CONFIG_BINFMT_ELF32) */ #if 0 printk("Using ELF interpreter %s\n", elf_interpreter); #endif @@ -607,13 +635,7 @@ elf_flags |= MAP_FIXED; } - down(¤t->mm->mmap_sem); - error = do_mmap(bprm->file, ELF_PAGESTART(load_bias + vaddr), - (elf_ppnt->p_filesz + - ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), - elf_prot, elf_flags, (elf_ppnt->p_offset - - ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); - up(¤t->mm->mmap_sem); + error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); if (!load_addr_set) { load_addr_set = 1; @@ -785,7 +807,7 @@ /* Now read in all of the header information */ j = sizeof(struct elf_phdr) * elf_ex.e_phnum; - if (j > ELF_EXEC_PAGESIZE) + if (j > ELF_MIN_ALIGN) goto out; error = -ENOMEM; @@ -824,8 +846,7 @@ elf_bss = k; padzero(elf_bss); - len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + - ELF_EXEC_PAGESIZE - 1); + len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1); bss = elf_phdata->p_memsz + elf_phdata->p_vaddr; if (bss > len) do_brk(len, bss - len); diff -urN linux-2.4.0-test4/fs/buffer.c linux-2.4.0-test4-lia/fs/buffer.c --- linux-2.4.0-test4/fs/buffer.c Tue Jul 11 14:29:02 2000 +++ linux-2.4.0-test4-lia/fs/buffer.c Fri Jul 28 23:16:06 2000 @@ -1620,9 +1620,9 @@ PAGE_CACHE_SIZE, get_block); if (status) goto out_unmap; - kaddr = (char*)page_address(page); + kaddr = (char*)page_address(new_page); memset(kaddr+zerofrom, 0, PAGE_CACHE_SIZE-zerofrom); - __block_commit_write(inode, new_page, zerofrom, to); + __block_commit_write(inode, new_page, zerofrom, PAGE_CACHE_SIZE); kunmap(new_page); UnlockPage(new_page); page_cache_release(new_page); diff -urN linux-2.4.0-test4/fs/dcache.c linux-2.4.0-test4-lia/fs/dcache.c --- linux-2.4.0-test4/fs/dcache.c Wed Jul 12 16:24:44 2000 +++ linux-2.4.0-test4-lia/fs/dcache.c Thu Jul 13 15:54:09 2000 @@ -1191,7 +1191,8 @@ if (!dentry_cache) panic("Cannot create dentry cache"); - mempages >>= (13 - PAGE_SHIFT); + if (PAGE_SHIFT < 13) + mempages >>= (13 - PAGE_SHIFT); mempages *= sizeof(struct list_head); for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++) ; diff -urN linux-2.4.0-test4/fs/nfsd/nfsfh.c linux-2.4.0-test4-lia/fs/nfsd/nfsfh.c --- linux-2.4.0-test4/fs/nfsd/nfsfh.c Sat Jul 8 19:26:13 2000 +++ linux-2.4.0-test4-lia/fs/nfsd/nfsfh.c Thu Jul 13 15:54:09 2000 @@ -379,7 +379,7 @@ /* It's a directory, or we are required to confirm the file's * location in the tree. */ - dprintk("nfs_fh: need to look harder for %d/%ld\n",sb->s_dev,ino); + dprintk("nfs_fh: need to look harder for %d/%ld\n",sb->s_dev,(long) ino); down(&sb->s_nfsd_free_path_sem); /* claiming the semaphore might have allowed things to get fixed up */ diff -urN linux-2.4.0-test4/include/asm-ia64/acpi-ext.h linux-2.4.0-test4-lia/include/asm-ia64/acpi-ext.h --- linux-2.4.0-test4/include/asm-ia64/acpi-ext.h Tue Feb 8 12:01:59 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/acpi-ext.h Fri Jul 28 23:16:20 2000 @@ -69,7 +69,7 @@ u8 eid; } acpi_entry_lsapic_t; -typedef struct { +typedef struct acpi_entry_iosapic { u8 type; u8 length; u16 reserved; diff -urN linux-2.4.0-test4/include/asm-ia64/efi.h linux-2.4.0-test4-lia/include/asm-ia64/efi.h --- linux-2.4.0-test4/include/asm-ia64/efi.h Fri Mar 10 15:24:02 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/efi.h Fri Jul 28 23:40:25 2000 @@ -226,6 +226,7 @@ } extern void efi_init (void); +extern void efi_map_pal_code (void); extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); extern void efi_gettimeofday (struct timeval *tv); extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ diff -urN linux-2.4.0-test4/include/asm-ia64/ia32.h linux-2.4.0-test4-lia/include/asm-ia64/ia32.h --- linux-2.4.0-test4/include/asm-ia64/ia32.h Tue Jul 11 19:02:37 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/ia32.h Fri Jul 28 23:16:34 2000 @@ -40,7 +40,6 @@ __kernel_off_t32 l_start; __kernel_off_t32 l_len; __kernel_pid_t32 l_pid; - short __unused; }; @@ -105,11 +104,21 @@ } sigset32_t; struct sigaction32 { - unsigned int sa_handler; /* Really a pointer, but need to deal - with 32 bits */ + unsigned int sa_handler; /* Really a pointer, but need to deal + with 32 bits */ unsigned int sa_flags; - unsigned int sa_restorer; /* Another 32 bit pointer */ - sigset32_t sa_mask; /* A 32 bit mask */ + unsigned int sa_restorer; /* Another 32 bit pointer */ + sigset32_t sa_mask; /* A 32 bit mask */ +}; + +typedef unsigned int old_sigset32_t; /* at least 32 bits */ + +struct old_sigaction32 { + unsigned int sa_handler; /* Really a pointer, but need to deal + with 32 bits */ + old_sigset32_t sa_mask; /* A 32 bit mask */ + unsigned int sa_flags; + unsigned int sa_restorer; /* Another 32 bit pointer */ }; typedef struct sigaltstack_ia32 { @@ -241,7 +250,7 @@ #define IA32_PAGE_OFFSET 0xc0000000 #define USE_ELF_CORE_DUMP -#define ELF_EXEC_PAGESIZE PAGE_SIZE +#define ELF_EXEC_PAGESIZE IA32_PAGE_SIZE /* * This is the location that an ET_DYN program is loaded if exec'ed. diff -urN linux-2.4.0-test4/include/asm-ia64/io.h linux-2.4.0-test4-lia/include/asm-ia64/io.h --- linux-2.4.0-test4/include/asm-ia64/io.h Fri Apr 21 15:21:24 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/io.h Fri Jul 28 23:37:15 2000 @@ -47,6 +47,10 @@ return (void *) (address + PAGE_OFFSET); } +/* + * The following two macros are deprecated and scheduled for removal. + * Please use the PCI-DMA interface defined in instead. + */ #define bus_to_virt phys_to_virt #define virt_to_bus virt_to_phys @@ -315,6 +319,7 @@ #define writeq(v,a) __writeq((v), (void *) (a)) #define __raw_writeb writeb #define __raw_writew writew +#define __raw_writel writel #define __raw_writeq writeq #ifndef inb_p diff -urN linux-2.4.0-test4/include/asm-ia64/machvec.h linux-2.4.0-test4-lia/include/asm-ia64/machvec.h --- linux-2.4.0-test4/include/asm-ia64/machvec.h Fri Mar 10 15:24:02 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/machvec.h Fri Jul 28 23:37:15 2000 @@ -4,8 +4,8 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Srinivasa Thirumalachar * Copyright (C) Vijay Chander - * Copyright (C) 1999 Hewlett-Packard Co. - * Copyright (C) David Mosberger-Tang + * Copyright (C) 1999-2000 Hewlett-Packard Co. + * Copyright (C) 1999-2000 David Mosberger-Tang */ #ifndef _ASM_IA64_MACHVEC_H #define _ASM_IA64_MACHVEC_H @@ -21,6 +21,7 @@ struct task_struct; struct timeval; struct vm_area_struct; +struct acpi_entry_iosapic; typedef void ia64_mv_setup_t (char **); typedef void ia64_mv_irq_init_t (void); @@ -30,15 +31,33 @@ typedef void ia64_mv_mca_handler_t (void); typedef void ia64_mv_cmci_handler_t (int, void *, struct pt_regs *); typedef void ia64_mv_log_print_t (void); +typedef void ia64_mv_register_iosapic_t (struct acpi_entry_iosapic *); + +extern void machvec_noop (void); # if defined (CONFIG_IA64_HP_SIM) # include # elif defined (CONFIG_IA64_DIG) # include # elif defined (CONFIG_IA64_SGI_SN1_SIM) -# include +# include # elif defined (CONFIG_IA64_GENERIC) +# ifdef MACHVEC_PLATFORM_HEADER +# include MACHVEC_PLATFORM_HEADER +# else +# define platform_name ia64_mv.name +# define platform_setup ia64_mv.setup +# define platform_irq_init ia64_mv.irq_init +# define platform_map_nr ia64_mv.map_nr +# define platform_mca_init ia64_mv.mca_init +# define platform_mca_handler ia64_mv.mca_handler +# define platform_cmci_handler ia64_mv.cmci_handler +# define platform_log_print ia64_mv.log_print +# define platform_pci_fixup ia64_mv.pci_fixup +# define platform_register_iosapic ia64_mv.register_iosapic +# endif + struct ia64_machine_vector { const char *name; ia64_mv_setup_t *setup; @@ -49,6 +68,7 @@ ia64_mv_mca_handler_t *mca_handler; ia64_mv_cmci_handler_t *cmci_handler; ia64_mv_log_print_t *log_print; + ia64_mv_register_iosapic_t *register_iosapic; }; #define MACHVEC_INIT(name) \ @@ -61,22 +81,12 @@ platform_mca_init, \ platform_mca_handler, \ platform_cmci_handler, \ - platform_log_print \ + platform_log_print, \ + platform_register_iosapic \ } -# ifndef MACHVEC_INHIBIT_RENAMING -# define platform_name ia64_mv.name -# define platform_setup ia64_mv.setup -# define platform_irq_init ia64_mv.irq_init -# define platform_map_nr ia64_mv.map_nr -# define platform_mca_init ia64_mv.mca_init -# define platform_mca_handler ia64_mv.mca_handler -# define platform_cmci_handler ia64_mv.cmci_handler -# define platform_log_print ia64_mv.log_print -# endif - extern struct ia64_machine_vector ia64_mv; -extern void machvec_noop (void); +extern void machvec_init (const char *name); # else # error Unknown configuration. Update asm-ia64/machvec.h. @@ -103,6 +113,12 @@ #endif #ifndef platform_log_print # define platform_log_print ((ia64_mv_log_print_t *) machvec_noop) +#endif +#ifndef platform_pci_fixup +# define platform_pci_fixup ((ia64_mv_pci_fixup_t *) machvec_noop) +#endif +#ifndef platform_register_iosapic +# define platform_register_iosapic ((ia64_mv_register_iosapic_t *) machvec_noop) #endif #endif /* _ASM_IA64_MACHVEC_H */ diff -urN linux-2.4.0-test4/include/asm-ia64/machvec_dig.h linux-2.4.0-test4-lia/include/asm-ia64/machvec_dig.h --- linux-2.4.0-test4/include/asm-ia64/machvec_dig.h Sun Feb 6 18:42:40 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/machvec_dig.h Fri Jul 28 23:16:59 2000 @@ -5,6 +5,7 @@ extern ia64_mv_irq_init_t dig_irq_init; extern ia64_mv_pci_fixup_t dig_pci_fixup; extern ia64_mv_map_nr_t map_nr_dense; +extern ia64_mv_register_iosapic_t dig_register_iosapic; /* * This stuff has dual use! @@ -18,5 +19,6 @@ #define platform_irq_init dig_irq_init #define platform_pci_fixup dig_pci_fixup #define platform_map_nr map_nr_dense +#define platform_register_iosapic dig_register_iosapic #endif /* _ASM_IA64_MACHVEC_DIG_h */ diff -urN linux-2.4.0-test4/include/asm-ia64/machvec_init.h linux-2.4.0-test4-lia/include/asm-ia64/machvec_init.h --- linux-2.4.0-test4/include/asm-ia64/machvec_init.h Sun Feb 6 18:42:40 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/machvec_init.h Fri Jul 28 23:17:05 2000 @@ -1,4 +1,6 @@ -#define MACHVEC_INHIBIT_RENAMING +#define __MACHVEC_HDR(n) +#define __MACHVEC_EXPAND(n) __MACHVEC_HDR(n) +#define MACHVEC_PLATFORM_HEADER __MACHVEC_EXPAND(MACHVEC_PLATFORM_NAME) #include @@ -7,3 +9,5 @@ = MACHVEC_INIT(name); #define MACHVEC_DEFINE(name) MACHVEC_HELPER(name) + +MACHVEC_DEFINE(MACHVEC_PLATFORM_NAME) diff -urN linux-2.4.0-test4/include/asm-ia64/offsets.h linux-2.4.0-test4-lia/include/asm-ia64/offsets.h --- linux-2.4.0-test4/include/asm-ia64/offsets.h Thu Jun 22 07:09:45 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/offsets.h Thu Jul 13 22:55:03 2000 @@ -8,20 +8,22 @@ * */ -#define PF_PTRACED_BIT 4 +#define PT_PTRACED_BIT 0 +#define PT_TRACESYS_BIT 1 -#define IA64_TASK_SIZE 2816 /* 0xb00 */ +#define IA64_TASK_SIZE 2768 /* 0xad0 */ #define IA64_PT_REGS_SIZE 400 /* 0x190 */ #define IA64_SWITCH_STACK_SIZE 560 /* 0x230 */ #define IA64_SIGINFO_SIZE 136 /* 0x88 */ +#define UNW_FRAME_INFO_SIZE 448 /* 0x1c0 */ -#define IA64_TASK_FLAGS_OFFSET 8 /* 0x8 */ +#define IA64_TASK_PTRACE_OFFSET 48 /* 0x30 */ #define IA64_TASK_SIGPENDING_OFFSET 16 /* 0x10 */ #define IA64_TASK_NEED_RESCHED_OFFSET 40 /* 0x28 */ -#define IA64_TASK_PROCESSOR_OFFSET 108 /* 0x6c */ -#define IA64_TASK_THREAD_OFFSET 928 /* 0x3a0 */ -#define IA64_TASK_THREAD_KSP_OFFSET 928 /* 0x3a0 */ -#define IA64_TASK_THREAD_SIGMASK_OFFSET 2656 /* 0xa60 */ +#define IA64_TASK_PROCESSOR_OFFSET 100 /* 0x64 */ +#define IA64_TASK_THREAD_OFFSET 896 /* 0x380 */ +#define IA64_TASK_THREAD_KSP_OFFSET 896 /* 0x380 */ +#define IA64_TASK_THREAD_SIGMASK_OFFSET 2648 /* 0xa58 */ #define IA64_TASK_PID_OFFSET 188 /* 0xbc */ #define IA64_TASK_MM_OFFSET 88 /* 0x58 */ #define IA64_PT_REGS_CR_IPSR_OFFSET 0 /* 0x0 */ diff -urN linux-2.4.0-test4/include/asm-ia64/page.h linux-2.4.0-test4-lia/include/asm-ia64/page.h --- linux-2.4.0-test4/include/asm-ia64/page.h Thu Jun 22 07:09:45 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/page.h Fri Jul 28 23:37:15 2000 @@ -100,6 +100,7 @@ #define MAP_NR_SN1(addr) (((unsigned long) (addr) - PAGE_OFFSET) >> PAGE_SHIFT) #ifdef CONFIG_IA64_GENERIC +# include # define MAP_NR(addr) platform_map_nr(addr) #elif defined (CONFIG_IA64_SN_SN1_SIM) # define MAP_NR(addr) MAP_NR_SN1(addr) diff -urN linux-2.4.0-test4/include/asm-ia64/pal.h linux-2.4.0-test4-lia/include/asm-ia64/pal.h --- linux-2.4.0-test4/include/asm-ia64/pal.h Thu Jun 22 07:09:45 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/pal.h Fri Jul 28 23:17:20 2000 @@ -18,7 +18,8 @@ * 00/03/07 davidm Updated pal_cache_flush() to be in sync with PAL v2.6. * 00/03/23 cfleck Modified processor min-state save area to match updated PAL & SAL info * 00/05/24 eranian Updated to latest PAL spec, fix structures bugs, added - * 00/05/25 eranian Support for stack calls, and statis physical calls + * 00/05/25 eranian Support for stack calls, and static physical calls + * 00/06/18 eranian Support for stacked physical calls */ /* @@ -646,10 +647,12 @@ extern struct ia64_pal_retval ia64_pal_call_static (u64, u64, u64, u64); extern struct ia64_pal_retval ia64_pal_call_stacked (u64, u64, u64, u64); extern struct ia64_pal_retval ia64_pal_call_phys_static (u64, u64, u64, u64); +extern struct ia64_pal_retval ia64_pal_call_phys_stacked (u64, u64, u64, u64); #define PAL_CALL(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_static(a0, a1, a2, a3) #define PAL_CALL_STK(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_stacked(a0, a1, a2, a3) #define PAL_CALL_PHYS(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_phys_static(a0, a1, a2, a3) +#define PAL_CALL_PHYS_STK(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_phys_stacked(a0, a1, a2, a3) typedef int (*ia64_pal_handler) (u64, ...); extern ia64_pal_handler ia64_pal; @@ -951,7 +954,7 @@ /* Return information about processor's optional power management capabilities. */ extern inline s64 ia64_pal_halt_info (pal_power_mgmt_info_u_t *power_buf) -{ +{ struct ia64_pal_retval iprv; PAL_CALL_STK(iprv, PAL_HALT_INFO, (unsigned long) power_buf, 0, 0); return iprv.status; @@ -1370,17 +1373,17 @@ dirty_bit_valid : 1, mem_attr_valid : 1, reserved : 60; - } pal_itr_valid_s; -} pal_itr_valid_u_t; + } pal_tr_valid_s; +} pal_tr_valid_u_t; /* Read a translation register */ extern inline s64 -ia64_pal_vm_tr_read (u64 reg_num, u64 tr_type, u64 tr_buffer, pal_itr_valid_u_t *itr_valid) -{ +ia64_pal_tr_read (u64 reg_num, u64 tr_type, u64 *tr_buffer, pal_tr_valid_u_t *tr_valid) +{ struct ia64_pal_retval iprv; - PAL_CALL(iprv, PAL_VM_TR_READ, reg_num, tr_type, tr_buffer); - if (itr_valid) - itr_valid->piv_val = iprv.v0; + PAL_CALL_PHYS_STK(iprv, PAL_VM_TR_READ, reg_num, tr_type,(u64)__pa(tr_buffer)); + if (tr_valid) + tr_valid->piv_val = iprv.v0; return iprv.status; } diff -urN linux-2.4.0-test4/include/asm-ia64/param.h linux-2.4.0-test4-lia/include/asm-ia64/param.h --- linux-2.4.0-test4/include/asm-ia64/param.h Sun Feb 6 18:42:40 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/param.h Fri Jul 28 23:37:15 2000 @@ -10,23 +10,13 @@ #include -#ifdef CONFIG_IA64_HP_SIM +#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_SOFTSDV_HACKS) /* * Yeah, simulating stuff is slow, so let us catch some breath between * timer interrupts... */ # define HZ 20 -#endif - -#ifdef CONFIG_IA64_DIG -# ifdef CONFIG_IA64_SOFTSDV_HACKS -# define HZ 20 -# else -# define HZ 100 -# endif -#endif - -#ifndef HZ +#else # define HZ 1024 #endif diff -urN linux-2.4.0-test4/include/asm-ia64/pci.h linux-2.4.0-test4-lia/include/asm-ia64/pci.h --- linux-2.4.0-test4/include/asm-ia64/pci.h Thu Jun 22 07:17:16 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/pci.h Fri Jul 28 23:39:07 2000 @@ -1,6 +1,15 @@ #ifndef _ASM_IA64_PCI_H #define _ASM_IA64_PCI_H +#include +#include +#include +#include +#include + +#include +#include + /* * Can be used to override the logic in pci_scan_bus for skipping * already-configured bus numbers - to be used for buggy BIOSes or @@ -11,6 +20,8 @@ #define PCIBIOS_MIN_IO 0x1000 #define PCIBIOS_MIN_MEM 0x10000000 +struct pci_dev; + extern inline void pcibios_set_master(struct pci_dev *dev) { /* No special bus mastering setup handling */ @@ -23,18 +34,8 @@ /* * Dynamic DMA mapping API. - * IA-64 has everything mapped statically. */ -#include -#include -#include - -#include -#include - -struct pci_dev; - /* * Allocate and map kernel buffer using consistent mode DMA for a device. * hwdev should be valid struct pci_dev pointer for PCI devices, @@ -64,13 +65,7 @@ * Once the device is given the dma address, the device owns this memory * until either pci_unmap_single or pci_dma_sync_single is performed. */ -extern inline dma_addr_t -pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - return virt_to_bus(ptr); -} +extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction); /* * Unmap a single streaming mode DMA translation. The dma_addr and size @@ -80,13 +75,7 @@ * After this call, reads by the cpu to the buffer are guarenteed to see * whatever the device wrote there. */ -extern inline void -pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - /* Nothing to do */ -} +extern void pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction); /* * Map a set of buffers described by scatterlist in streaming @@ -104,26 +93,14 @@ * Device ownership issues as mentioned above for pci_map_single are * the same here. */ -extern inline int -pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - return nents; -} +extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction); /* * Unmap a set of streaming mode DMA translations. * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -extern inline void -pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - /* Nothing to do */ -} +extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction); /* * Make physical memory consistent for a single @@ -135,13 +112,7 @@ * next point you give the PCI dma address back to the card, the * device again owns the buffer. */ -extern inline void -pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - /* Nothing to do */ -} +extern void pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction); /* * Make physical memory consistent for a set of streaming mode DMA @@ -150,20 +121,15 @@ * The same as pci_dma_sync_single but for a scatter-gather list, * same rules and usage. */ -extern inline void -pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - /* Nothing to do */ -} +extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); /* Return whether the given PCI device DMA address mask can * be supported properly. For example, if your device can * only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +extern inline int +pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) { return 1; } diff -urN linux-2.4.0-test4/include/asm-ia64/pgtable.h linux-2.4.0-test4-lia/include/asm-ia64/pgtable.h --- linux-2.4.0-test4/include/asm-ia64/pgtable.h Fri Jun 23 21:11:20 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/pgtable.h Fri Jul 28 23:39:06 2000 @@ -111,6 +111,7 @@ #include #include +#include #include /* @@ -304,6 +305,21 @@ a.l = address; return a.f.reg; } + +/* + * Return the region offset for virtual address ADDRESS. + */ +extern __inline__ unsigned long +rgn_offset (unsigned long address) +{ + ia64_va a; + + a.l = address; + return a.f.off; +} + +#define RGN_SIZE (1UL << 61) +#define RGN_KERNEL 7 extern __inline__ unsigned long pgd_index (unsigned long address) diff -urN linux-2.4.0-test4/include/asm-ia64/processor.h linux-2.4.0-test4-lia/include/asm-ia64/processor.h --- linux-2.4.0-test4/include/asm-ia64/processor.h Thu Jun 22 07:09:45 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/processor.h Fri Jul 28 23:39:06 2000 @@ -338,8 +338,12 @@ struct mm_struct; struct task_struct; -/* Free all resources held by a thread. */ -extern void release_thread (struct task_struct *); +/* + * Free all resources held by a thread. This is called after the + * parent of DEAD_TASK has collected the exist status of the task via + * wait(). This is a no-op on IA-64. + */ +#define release_thread(dead_task) /* * This is the mechanism for creating a new kernel thread. diff -urN linux-2.4.0-test4/include/asm-ia64/scatterlist.h linux-2.4.0-test4-lia/include/asm-ia64/scatterlist.h --- linux-2.4.0-test4/include/asm-ia64/scatterlist.h Sun Feb 6 18:42:40 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/scatterlist.h Fri Jul 28 23:18:13 2000 @@ -13,6 +13,7 @@ * indirection buffer, NULL otherwise: */ char *alt_address; + char *orig_address; /* Save away the original buffer address (used by pci-dma.c) */ unsigned int length; /* buffer length */ }; diff -urN linux-2.4.0-test4/include/asm-ia64/smp.h linux-2.4.0-test4-lia/include/asm-ia64/smp.h --- linux-2.4.0-test4/include/asm-ia64/smp.h Fri Apr 21 15:21:24 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/smp.h Fri Jul 28 23:39:06 2000 @@ -99,5 +99,9 @@ extern void __init init_smp_config (void); extern void smp_do_timer (struct pt_regs *regs); +extern int smp_call_function_single (int cpuid, void (*func) (void *info), void *info, + int retry, int wait); + + #endif /* CONFIG_SMP */ #endif /* _ASM_IA64_SMP_H */ diff -urN linux-2.4.0-test4/include/asm-ia64/string.h linux-2.4.0-test4-lia/include/asm-ia64/string.h --- linux-2.4.0-test4/include/asm-ia64/string.h Thu Jun 22 07:09:45 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/string.h Thu Jul 13 15:54:09 2000 @@ -5,14 +5,17 @@ * Here is where we want to put optimized versions of the string * routines. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang */ #define __HAVE_ARCH_STRLEN 1 /* see arch/ia64/lib/strlen.S */ #define __HAVE_ARCH_MEMSET 1 /* see arch/ia64/lib/memset.S */ +#define __HAVE_ARCH_MEMCPY 1 /* see arch/ia64/lib/memcpy.S */ +#define __HAVE_ARCH_BCOPY 1 /* see arch/ia64/lib/memcpy.S */ extern __kernel_size_t strlen (const char *); -extern void *memset (void *,int,__kernel_size_t); +extern void *memset (void *, int, __kernel_size_t); +extern void *memcpy (void *, const void *, __kernel_size_t); #endif /* _ASM_IA64_STRING_H */ diff -urN linux-2.4.0-test4/include/asm-ia64/system.h linux-2.4.0-test4-lia/include/asm-ia64/system.h --- linux-2.4.0-test4/include/asm-ia64/system.h Thu Jun 22 07:09:45 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/system.h Fri Jul 28 23:37:15 2000 @@ -445,6 +445,7 @@ */ # define switch_to(prev,next,last) do { \ if (ia64_get_fpu_owner() == (prev) && ia64_psr(ia64_task_regs(prev))->mfh) { \ + ia64_psr(ia64_task_regs(prev))->mfh = 0; \ (prev)->thread.flags |= IA64_THREAD_FPH_VALID; \ __ia64_save_fpu((prev)->thread.fph); \ } \ diff -urN linux-2.4.0-test4/include/asm-ia64/unistd.h linux-2.4.0-test4-lia/include/asm-ia64/unistd.h --- linux-2.4.0-test4/include/asm-ia64/unistd.h Thu Jun 22 07:09:45 2000 +++ linux-2.4.0-test4-lia/include/asm-ia64/unistd.h Thu Jul 13 15:54:09 2000 @@ -4,8 +4,8 @@ /* * IA-64 Linux syscall numbers and inline-functions. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang */ #include @@ -202,6 +202,7 @@ #define __NR_stat 1210 #define __NR_lstat 1211 #define __NR_fstat 1212 +#define __NR_clone2 1213 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) diff -urN linux-2.4.0-test4/include/linux/irq.h linux-2.4.0-test4-lia/include/linux/irq.h --- linux-2.4.0-test4/include/linux/irq.h Fri Jul 14 17:19:28 2000 +++ linux-2.4.0-test4-lia/include/linux/irq.h Fri Jul 28 23:39:06 2000 @@ -56,6 +56,7 @@ #include /* the arch dependent stuff */ +extern unsigned int do_IRQ (unsigned long irq, struct pt_regs *regs); extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); extern int setup_irq(unsigned int , struct irqaction * ); diff -urN linux-2.4.0-test4/include/linux/mmzone.h linux-2.4.0-test4-lia/include/linux/mmzone.h --- linux-2.4.0-test4/include/linux/mmzone.h Fri Jul 14 17:19:28 2000 +++ linux-2.4.0-test4-lia/include/linux/mmzone.h Fri Jul 28 23:37:15 2000 @@ -26,10 +26,10 @@ * Commonly accessed fields: */ spinlock_t lock; - unsigned long offset; - unsigned long free_pages; char low_on_memory; char zone_wake_kswapd; + unsigned long offset; + unsigned long free_pages; unsigned long pages_min, pages_low, pages_high; /* diff -urN linux-2.4.0-test4/include/linux/sched.h linux-2.4.0-test4-lia/include/linux/sched.h --- linux-2.4.0-test4/include/linux/sched.h Fri Jul 14 17:19:28 2000 +++ linux-2.4.0-test4-lia/include/linux/sched.h Fri Jul 28 23:39:06 2000 @@ -712,7 +712,8 @@ return err; } -extern int copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); +extern int copy_thread(int, unsigned long, unsigned long, unsigned long, struct task_struct *, + struct pt_regs *); extern void flush_thread(void); extern void exit_thread(void); @@ -723,7 +724,7 @@ extern void daemonize(void); extern int do_execve(char *, char **, char **, struct pt_regs *); -extern int do_fork(unsigned long, unsigned long, struct pt_regs *); +extern int do_fork(unsigned long, unsigned long, unsigned long, struct pt_regs *); static inline void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) { diff -urN linux-2.4.0-test4/init/main.c linux-2.4.0-test4-lia/init/main.c --- linux-2.4.0-test4/init/main.c Tue Jul 11 11:17:46 2000 +++ linux-2.4.0-test4-lia/init/main.c Thu Jul 13 23:48:23 2000 @@ -113,6 +113,9 @@ #if defined(CONFIG_QUOTA) extern void dquot_init_hash(void); #endif +#ifdef CONFIG_PERFMON +extern void perfmon_init(void); +#endif /* * Boot command-line arguments @@ -554,6 +557,9 @@ #endif mem_init(); kmem_cache_sizes_init(); +#ifdef CONFIG_PERFMON + perfmon_init(); +#endif #ifdef CONFIG_3215_CONSOLE con3215_activate(); #endif @@ -581,7 +587,6 @@ #endif check_bugs(); printk("POSIX conformance testing by UNIFIX\n"); - /* * We count on the initial thread going ok * Like idlers init is an unlocked kernel thread, which will diff -urN linux-2.4.0-test4/kernel/fork.c linux-2.4.0-test4-lia/kernel/fork.c --- linux-2.4.0-test4/kernel/fork.c Fri Jul 7 14:20:21 2000 +++ linux-2.4.0-test4-lia/kernel/fork.c Thu Jul 13 15:54:09 2000 @@ -614,10 +614,15 @@ /* * Ok, this is the main fork-routine. It copies the system process - * information (task[nr]) and sets up the necessary registers. It - * also copies the data segment in its entirety. + * information (task[nr]) and sets up the necessary registers. It also + * copies the data segment in its entirety. The "stack_start" and + * "stack_top" arguments are simply passed along to the platform + * specific copy_thread() routine. Most platforms ignore stack_top. + * For an example that's using stack_top, see + * arch/ia64/kernel/process.c. */ -int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) +int do_fork(unsigned long clone_flags, unsigned long stack_start, unsigned long stack_top, + struct pt_regs *regs) { int retval = -ENOMEM; struct task_struct *p; @@ -724,7 +729,7 @@ goto bad_fork_cleanup_fs; if (copy_mm(clone_flags, p)) goto bad_fork_cleanup_sighand; - retval = copy_thread(0, clone_flags, usp, p, regs); + retval = copy_thread(0, clone_flags, stack_start, stack_top, p, regs); if (retval) goto bad_fork_cleanup_sighand; p->semundo = NULL; diff -urN linux-2.4.0-test4/kernel/printk.c linux-2.4.0-test4-lia/kernel/printk.c --- linux-2.4.0-test4/kernel/printk.c Wed Jul 5 11:00:21 2000 +++ linux-2.4.0-test4-lia/kernel/printk.c Thu Jul 13 23:48:35 2000 @@ -14,6 +14,8 @@ * manfreds@colorfullife.com */ +#include + #include #include #include @@ -296,6 +298,12 @@ break; } } +#ifdef CONFIG_IA64_EARLY_PRINTK + if (!console_drivers) { + static void early_printk (const char *str); + early_printk(msg); + } else +#endif if (msg_level < console_loglevel && console_drivers) { struct console *c = console_drivers; while(c) { @@ -412,6 +420,10 @@ } if ((console->flags & CON_PRINTBUFFER) == 0) goto done; +#ifdef CONFIG_IA64_EARLY_PRINTK + goto done; +#endif + /* * Print out buffered log messages. */ @@ -495,3 +507,47 @@ tty->driver.write(tty, 0, msg, strlen(msg)); return; } + +#ifdef CONFIG_IA64_EARLY_PRINTK + +#include + +#define VGABASE ((char *)0x00000000000b8000) + +static int current_ypos = 50, current_xpos = 0; + +void +early_printk (const char *str) +{ + char c; + int i, k, j; + + while ((c = *str++) != '\0') { + if (current_ypos >= 50) { + /* scroll 1 line up */ + for (k = 1, j = 0; k < 50; k++, j++) { + for (i = 0; i < 80; i++) { + writew(readw(VGABASE + 2*(80*k + i)), + VGABASE + 2*(80*j + i)); + } + } + for (i = 0; i < 80; i++) { + writew(0x720, VGABASE + 2*(80*j + i)); + } + current_ypos = 49; + } + if (c == '\n') { + current_xpos = 0; + current_ypos++; + } else if (c != '\r') { + writew(((0x7 << 8) | (unsigned short) c), + VGABASE + 2*(80*current_ypos + current_xpos++)); + if (current_xpos >= 80) { + current_xpos = 0; + current_ypos++; + } + } + } +} + +#endif /* CONFIG_IA64_EARLY_PRINTK */ diff -urN linux-2.4.0-test4/kernel/timer.c linux-2.4.0-test4-lia/kernel/timer.c --- linux-2.4.0-test4/kernel/timer.c Tue Jul 11 09:25:36 2000 +++ linux-2.4.0-test4-lia/kernel/timer.c Thu Jul 13 15:57:16 2000 @@ -665,7 +665,7 @@ void do_timer(struct pt_regs *regs) { - (*(unsigned long *)&jiffies)++; + (*(volatile unsigned long *)&jiffies)++; update_process_times(user_mode(regs)); mark_bh(TIMER_BH); if (tq_timer) diff -urN linux-2.4.0-test4/lib/cmdline.c linux-2.4.0-test4-lia/lib/cmdline.c --- linux-2.4.0-test4/lib/cmdline.c Tue Jun 20 07:52:36 2000 +++ linux-2.4.0-test4-lia/lib/cmdline.c Fri Jul 28 23:19:54 2000 @@ -85,12 +85,12 @@ * @ptr: Where parse begins * @retptr: (output) Pointer to next char after parse completes * - * Parses a string into a number. The number stored - * at @ptr is potentially suffixed with %K (for - * kilobytes, or 1024 bytes) or suffixed with %M (for - * megabytes, or 1048576 bytes). If the number is suffixed - * with K or M, then the return value is the number - * multiplied by one kilobyte, or one megabyte, respectively. + * Parses a string into a number. The number stored at @ptr is + * potentially suffixed with %K (for kilobytes, or 1024 bytes), + * %M (for megabytes, or 1048576 bytes), or %G (for gigabytes, or + * 1073741824). If the number is suffixed with K, M, or G, then + * the return value is the number multiplied by one kilobyte, one + * megabyte, or one gigabyte, respectively. */ unsigned long memparse (char *ptr, char **retptr) @@ -98,6 +98,9 @@ unsigned long ret = simple_strtoul (ptr, retptr, 0); switch (**retptr) { + case 'G': + case 'g': + ret <<= 10; case 'M': case 'm': ret <<= 10;