diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-11-23 02:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-11-23 02:00:47 +0000 |
commit | 06615f62b17d7de6e12d2f5ec6b88cf30af08413 (patch) | |
tree | 8766f208847d4876a6db619aebbf54d53b76eb44 /arch/ia64 | |
parent | fa9bdb574f4febb751848a685d9a9017e04e1d53 (diff) |
Merge with Linux 2.4.0-test10.
Diffstat (limited to 'arch/ia64')
47 files changed, 1578 insertions, 828 deletions
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index d542d1487..0a1714c35 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -14,13 +14,18 @@ AWK := awk export AWK LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds -AFLAGS += -Wa,-x +AFLAGS += -Wa,-x +AFLAGS_KERNEL := -mconstant-gp EXTRA = CFLAGS := $(CFLAGS) -pipe $(EXTRA) -Wa,-x -ffixed-r13 -mfixed-range=f10-f15,f32-f127 \ -funwind-tables CFLAGS_KERNEL := -mconstant-gp +ifeq ($(CONFIG_ITANIUM_ASTEP_SPECIFIC),y) + CFLAGS += -ma-step +endif + ifdef CONFIG_IA64_GENERIC CORE_FILES := arch/$(ARCH)/hp/hp.a \ arch/$(ARCH)/sn/sn.a \ @@ -41,11 +46,18 @@ ifdef CONFIG_IA64_HP_SIM $(CORE_FILES) endif -ifdef CONFIG_IA64_SGI_SN1_SIM +ifdef CONFIG_IA64_SGI_SN1 +CFLAGS := $(CFLAGS) -DSN -I. -DBRINGUP -DDIRECT_L1_CONSOLE \ + -DNUMA_BASE -DSIMULATED_KLGRAPH -DNUMA_MIGR_CONTROL \ + -DLITTLE_ENDIAN -DREAL_HARDWARE -DLANGUAGE_C=1 \ + -D_LANGUAGE_C=1 SUBDIRS := arch/$(ARCH)/sn/sn1 \ arch/$(ARCH)/sn \ + arch/$(ARCH)/sn/io \ + arch/$(ARCH)/sn/fprom \ $(SUBDIRS) CORE_FILES := arch/$(ARCH)/sn/sn.a \ + arch/$(ARCH)/sn/io/sgiio.o\ $(CORE_FILES) endif diff --git a/arch/ia64/boot/bootloader.c b/arch/ia64/boot/bootloader.c index b73f396dc..5d1778ee3 100644 --- a/arch/ia64/boot/bootloader.c +++ b/arch/ia64/boot/bootloader.c @@ -68,15 +68,16 @@ cons_write (const char *buf) void enter_virtual_mode (unsigned long new_psr) { + long tmp; + + asm volatile ("movl %0=1f" : "=r"(tmp)); asm volatile ("mov cr.ipsr=%0" :: "r"(new_psr)); - asm volatile ("mov cr.iip=%0" :: "r"(&&target)); + asm volatile ("mov cr.iip=%0" :: "r"(tmp)); asm volatile ("mov cr.ifs=r0"); - asm volatile ("rfi;;"); /* must be last insn in an insn group */ - - target: + asm volatile ("rfi;;"); + asm volatile ("1:"); } - #define MAX_ARGS 32 void @@ -96,7 +97,7 @@ _start (void) char *kpath, *args; long arglen = 0; - asm volatile ("movl gp=__gp" ::: "memory"); + asm volatile ("movl gp=__gp;;" ::: "memory"); asm volatile ("mov sp=%0" :: "r"(stack) : "memory"); asm volatile ("bsw.1;;"); #ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC diff --git a/arch/ia64/config.in b/arch/ia64/config.in index 97d622276..33bf47a44 100644 --- a/arch/ia64/config.in +++ b/arch/ia64/config.in @@ -27,7 +27,7 @@ choice 'IA-64 system type' \ "generic CONFIG_IA64_GENERIC \ DIG-compliant CONFIG_IA64_DIG \ HP-simulator CONFIG_IA64_HP_SIM \ - SN1-simulator CONFIG_IA64_SGI_SN1_SIM" generic + SGI-SN1 CONFIG_IA64_SGI_SN1" generic choice 'Kernel page size' \ "4KB CONFIG_IA64_PAGE_SIZE_4KB \ @@ -51,11 +51,30 @@ if [ "$CONFIG_IA64_DIG" = "y" ]; then bool ' Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS bool ' Enable AzusA hacks' CONFIG_IA64_AZUSA_HACKS bool ' Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA + bool ' Force socket buffers below 4GB?' CONFIG_SKB_BELOW_4GB + + bool ' ACPI kernel configuration manager (EXPERIMENTAL)' CONFIG_ACPI_KERNEL_CONFIG + if [ "$CONFIG_ACPI_KERNEL_CONFIG" = "y" ]; then + define_bool CONFIG_PM y + define_bool CONFIG_ACPI y + define_bool CONFIG_ACPI_INTERPRETER y + fi fi -if [ "$CONFIG_IA64_SGI_SN1_SIM" = "y" ]; then - define_bool CONFIG_NUMA y - define_bool CONFIG_IA64_SOFTSDV_HACKS y +if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then + bool ' Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG + bool ' Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC + if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then + bool ' Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC + fi + bool ' Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM n + bool ' Enable SGI hack for version 1.0 syngery bugs' CONFIG_IA64_SGI_SYNERGY_1_0_HACKS n + define_bool CONFIG_DEVFS_DEBUG y + define_bool CONFIG_DEVFS_FS y + define_bool CONFIG_IA64_BRL_EMU y + define_bool CONFIG_IA64_MCA y + define_bool CONFIG_IA64_SGI_IO y + define_bool CONFIG_ITANIUM y fi define_bool CONFIG_KCORE_ELF y # On IA-64, we always want an ELF /proc/kcore. @@ -161,6 +180,10 @@ endmenu fi # !HP_SIM +# +# input before char - char/joystick depends on it. As does USB. +# +source drivers/input/Config.in source drivers/char/Config.in #source drivers/misc/Config.in @@ -192,7 +215,6 @@ fi endmenu source drivers/usb/Config.in -source drivers/input/Config.in fi # !HP_SIM @@ -226,5 +248,6 @@ bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXC bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS bool 'Enable new unwind support' CONFIG_IA64_NEW_UNWIND +bool 'Disable VHPT' CONFIG_DISABLE_VHPT endmenu diff --git a/arch/ia64/dig/iosapic.c b/arch/ia64/dig/iosapic.c index 7d9a084fd..18c7713bd 100644 --- a/arch/ia64/dig/iosapic.c +++ b/arch/ia64/dig/iosapic.c @@ -31,6 +31,10 @@ #include <asm/ptrace.h> #include <asm/system.h> +#ifdef CONFIG_ACPI_KERNEL_CONFIG +# include <asm/acpikcfg.h> +#endif + #undef DEBUG_IRQ_ROUTING static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED; @@ -228,7 +232,7 @@ iosapic_init (unsigned long address, int irqbase) { struct hw_interrupt_type *irq_type; struct pci_vector_struct *vectors; - int i, irq; + int i, irq, num_pci_vectors; if (irqbase == 0) /* @@ -255,9 +259,14 @@ iosapic_init (unsigned long address, int irqbase) * Map the PCI Interrupt data into the ACPI IOSAPIC data using * the info that the bootstrap loader passed to us. */ +# ifdef CONFIG_ACPI_KERNEL_CONFIG + acpi_cf_get_pci_vectors(&vectors, &num_pci_vectors); +# else ia64_boot_param.pci_vectors = (__u64) __va(ia64_boot_param.pci_vectors); vectors = (struct pci_vector_struct *) ia64_boot_param.pci_vectors; - for (i = 0; i < ia64_boot_param.num_pci_vectors; i++) { + num_pci_vectors = ia64_boot_param.num_pci_vectors; +# endif + for (i = 0; i < num_pci_vectors; i++) { irq = vectors[i].irq; if (irq < 16) irq = isa_irq_to_vector(irq); @@ -277,11 +286,11 @@ iosapic_init (unsigned long address, int irqbase) iosapic_trigger(irq) = IO_SAPIC_LEVEL; iosapic_polarity(irq) = IO_SAPIC_POL_LOW; -#ifdef DEBUG_IRQ_ROUTING +# ifdef DEBUG_IRQ_ROUTING printk("PCI: BUS %d Slot %x Pin %x IRQ %02x --> Vector %02x IOSAPIC Pin %d\n", vectors[i].bus, vectors[i].pci_id>>16, vectors[i].pin, vectors[i].irq, irq, iosapic_pin(irq)); -#endif +# endif } #endif /* CONFIG_IA64_SOFTSDV_HACKS */ @@ -377,7 +386,7 @@ dig_register_iosapic (acpi_entry_iosapic_t *iosapic) unsigned int ver, v; int l, max_pin; - ver = iosapic_version(iosapic->address); + ver = iosapic_version((unsigned long) ioremap(iosapic->address, 0)); max_pin = (ver >> 16) & 0xff; printk("IOSAPIC Version %x.%x: address 0x%lx IRQs 0x%x - 0x%x\n", diff --git a/arch/ia64/hp/hpsim_console.c b/arch/ia64/hp/hpsim_console.c index b97116cee..4f56dc829 100644 --- a/arch/ia64/hp/hpsim_console.c +++ b/arch/ia64/hp/hpsim_console.c @@ -28,17 +28,13 @@ static int simcons_wait_key (struct console *); static kdev_t simcons_console_device (struct console *); struct console hpsim_cons = { - "simcons", - simcons_write, /* write */ - NULL, /* read */ - simcons_console_device, /* device */ - simcons_wait_key, /* wait_key */ - NULL, /* unblank */ - simcons_init, /* setup */ - CON_PRINTBUFFER, /* flags */ - -1, /* index */ - 0, /* cflag */ - NULL /* next */ + name: "simcons", + write: simcons_write, + device: simcons_console_device, + wait_key: simcons_wait_key, + setup: simcons_init, + flags: CON_PRINTBUFFER, + index: -1, }; static int diff --git a/arch/ia64/ia32/Makefile b/arch/ia64/ia32/Makefile index 4f3312c01..23ffbd0d9 100644 --- a/arch/ia64/ia32/Makefile +++ b/arch/ia64/ia32/Makefile @@ -3,9 +3,9 @@ # .S.s: - $(CPP) $(AFLAGS) -o $*.s $< + $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $< .S.o: - $(CC) $(AFLAGS) -c -o $*.o $< + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< all: ia32.o diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c index 770ef6363..384747f8b 100644 --- a/arch/ia64/ia32/binfmt_elf32.c +++ b/arch/ia64/ia32/binfmt_elf32.c @@ -52,7 +52,7 @@ put_shared_page(struct task_struct * tsk, struct page *page, unsigned long addre pte_t * pte; if (page_count(page) != 1) - printk("mem_map disagrees with %p at %08lx\n", page, address); + printk("mem_map disagrees with %p at %08lx\n", (void *) page, address); pgd = pgd_offset(tsk->mm, address); pmd = pmd_alloc(pgd, address); if (!pmd) { @@ -120,6 +120,8 @@ void ia64_elf32_init(struct pt_regs *regs) : "r" ((ulong)IA32_FCR_DEFAULT)); __asm__("mov ar.fir = r0"); __asm__("mov ar.fdr = r0"); + __asm__("mov %0=ar.k0 ;;" : "=r" (current->thread.old_iob)); + __asm__("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE)); /* TSS */ __asm__("mov ar.k1 = %0" : /* no outputs */ diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c index 574c1937f..7b2a9f3ec 100644 --- a/arch/ia64/ia32/ia32_signal.c +++ b/arch/ia64/ia32/ia32_signal.c @@ -278,7 +278,7 @@ setup_frame_ia32(int sig, struct k_sigaction *ka, sigset_t *set, err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]); - if (_NSIG_WORDS > 1) { + if (_IA32_NSIG_WORDS > 1) { err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); } @@ -310,7 +310,7 @@ setup_frame_ia32(int sig, struct k_sigaction *ka, sigset_t *set, #if 0 printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n", - current->comm, current->pid, sig, frame, regs->cr_iip, frame->pretcode); + current->comm, current->pid, sig, (void *) frame, regs->cr_iip, frame->pretcode); #endif return 1; @@ -380,7 +380,7 @@ setup_rt_frame_ia32(int sig, struct k_sigaction *ka, siginfo_t *info, #if 0 printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n", - current->comm, current->pid, frame, regs->cr_iip, frame->pretcode); + current->comm, current->pid, (void *) frame, regs->cr_iip, frame->pretcode); #endif return 1; diff --git a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c index ab5bebfe1..bc02579ae 100644 --- a/arch/ia64/ia32/ia32_support.c +++ b/arch/ia64/ia32/ia32_support.c @@ -42,6 +42,7 @@ ia32_save_state (struct thread_struct *thread) thread->csd = csd; thread->ssd = ssd; thread->tssd = tssd; + asm ("mov ar.k0=%0 ;;" :: "r"(thread->old_iob)); } void @@ -68,6 +69,8 @@ ia32_load_state (struct thread_struct *thread) "mov ar.k1=%7" :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd), "r"(tssd)); + asm ("mov %0=ar.k0 ;;" : "=r"(thread->old_iob)); + asm ("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE)); } /* diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index a6bf4a8d8..0383741a0 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -75,11 +75,11 @@ nargs(unsigned int arg, char **ap) n = 0; do { err = get_user(addr, (int *)A(arg)); - if (IS_ERR(err)) + if (err) return err; if (ap) { /* no access_ok needed, we allocated */ err = __put_user((char *)A(addr), ap++); - if (IS_ERR(err)) + if (err) return err; } arg += sizeof(unsigned int); @@ -102,13 +102,14 @@ int stack) { struct pt_regs *regs = (struct pt_regs *)&stack; char **av, **ae; - int na, ne, r, len; + int na, ne, len; + long r; na = nargs(argv, NULL); - if (IS_ERR(na)) + if (na < 0) return(na); ne = nargs(envp, NULL); - if (IS_ERR(ne)) + if (ne < 0) return(ne); len = (na + ne + 2) * sizeof(*av); /* @@ -130,19 +131,19 @@ int stack) return (long)av; ae = av + na + 1; r = __put_user(0, (av + na)); - if (IS_ERR(r)) + if (r) goto out; r = __put_user(0, (ae + ne)); - if (IS_ERR(r)) + if (r) goto out; r = nargs(argv, av); - if (IS_ERR(r)) + if (r < 0) goto out; r = nargs(envp, ae); - if (IS_ERR(r)) + if (r < 0) goto out; r = sys_execve(filename, av, ae, regs); - if (IS_ERR(r)) + if (r < 0) out: sys_munmap((unsigned long) av, len); return(r); @@ -297,7 +298,7 @@ ia32_do_mmap (struct file *file, unsigned int addr, unsigned int len, unsigned i error = do_mmap(file, addr, len, prot, flags, poff); up(¤t->mm->mmap_sem); - if (!IS_ERR(error)) + if (!IS_ERR((void *) error)) error += offset - poff; } else { down(¤t->mm->mmap_sem); @@ -788,7 +789,8 @@ out: } static int -fillonedir32 (void * __buf, const char * name, int namlen, off_t offset, ino_t ino) +fillonedir32 (void * __buf, const char * name, int namlen, off_t offset, ino_t ino, + unsigned int d_type) { struct readdir32_callback * buf = (struct readdir32_callback *) __buf; struct old_linux32_dirent * dirent; @@ -2545,6 +2547,78 @@ sys32_ni_syscall(int dummy0, int dummy1, int dummy2, int dummy3, return(sys_ni_syscall()); } +/* + * The IA64 maps 4 I/O ports for each 4K page + */ +#define IOLEN ((65536 / 4) * 4096) + +asmlinkage long +sys_iopl (int level, long arg1, long arg2, long arg3) +{ + extern unsigned long ia64_iobase; + int fd; + struct file * file; + unsigned int old; + unsigned long addr; + mm_segment_t old_fs = get_fs (); + + if (level != 3) + return(-EINVAL); + /* Trying to gain more privileges? */ + __asm__ __volatile__("mov %0=ar.eflag ;;" : "=r"(old)); + if (level > ((old >> 12) & 3)) { + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + } + set_fs(KERNEL_DS); + fd = sys_open("/dev/mem", O_SYNC | O_RDWR, 0); + set_fs(old_fs); + if (fd < 0) + return fd; + file = fget(fd); + if (file == NULL) { + sys_close(fd); + return(-EFAULT); + } + + down(¤t->mm->mmap_sem); + lock_kernel(); + + addr = do_mmap_pgoff(file, IA32_IOBASE, + IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED, + (ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT); + + unlock_kernel(); + up(¤t->mm->mmap_sem); + + if (addr >= 0) { + __asm__ __volatile__("mov ar.k0=%0 ;;" :: "r"(addr)); + old = (old & ~0x3000) | (level << 12); + __asm__ __volatile__("mov ar.eflag=%0 ;;" :: "r"(old)); + } + + fput(file); + sys_close(fd); + return 0; +} + +asmlinkage long +sys_ioperm (unsigned long from, unsigned long num, int on) +{ + + /* + * Since IA64 doesn't have permission bits we'd have to go to + * a lot of trouble to simulate them in software. There's + * no point, only trusted programs can make this call so we'll + * just turn it into an iopl call and let the process have + * access to all I/O ports. + * + * XXX proper ioperm() support should be emulated by + * manipulating the page protections... + */ + return(sys_iopl(3, 0, 0, 0)); +} + #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ /* In order to reduce some races, while at the same time doing additional diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index 563c308ea..7a49511d3 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -3,9 +3,9 @@ # .S.s: - $(CPP) $(AFLAGS) -o $*.s $< + $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $< .S.o: - $(CC) $(AFLAGS) -c -o $*.o $< + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< all: kernel.o head.o init_task.o @@ -16,7 +16,7 @@ obj-y := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt obj-$(CONFIG_IA64_GENERIC) += machvec.o obj-$(CONFIG_IA64_PALINFO) += palinfo.o obj-$(CONFIG_PCI) += pci.o -obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_SMP) += smp.o smpboot.o obj-$(CONFIG_IA64_MCA) += mca.o mca_asm.o obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 4bba56e1d..a8c1ead1f 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -24,18 +24,17 @@ #include <asm/iosapic.h> #include <asm/machvec.h> #include <asm/page.h> +#ifdef CONFIG_ACPI_KERNEL_CONFIG +# include <asm/acpikcfg.h> +#endif #undef ACPI_DEBUG /* Guess what this does? */ -#ifdef CONFIG_SMP -extern struct smp_boot_data smp; -#endif - /* These are ugly but will be reclaimed by the kernel */ -int __initdata available_cpus = 0; -int __initdata total_cpus = 0; +int __initdata available_cpus; +int __initdata total_cpus; -void (*pm_idle) (void); +void (*pm_idle)(void); /* * Identify usable CPU's and remember them for SMP bringup later. @@ -60,18 +59,16 @@ acpi_lsapic(char *p) add = 0; } +#ifdef CONFIG_SMP + smp_boot_data.cpu_phys_id[total_cpus] = -1; +#endif if (add) { printk("Available.\n"); available_cpus++; #ifdef CONFIG_SMP -# if LARGE_CPU_ID_OK - smp.cpu_map[total_cpus] = (lsapic->id << 8) | lsapic->eid; -# else - smp.cpu_map[total_cpus] = lsapic->id; -# endif -#endif + smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid; +#endif /* CONFIG_SMP */ } - total_cpus++; } @@ -139,13 +136,12 @@ acpi_legacy_irq(char *p) break; } -#if 1/*def ACPI_DEBUG*/ +# ifdef ACPI_DEBUG printk("Legacy ISA IRQ %x -> IA64 Vector %x IOSAPIC Pin %x Active %s %s Trigger\n", legacy->isa_irq, vector, iosapic_pin(vector), ((iosapic_polarity(vector) == IO_SAPIC_POL_LOW) ? "Low" : "High"), ((iosapic_trigger(vector) == IO_SAPIC_LEVEL) ? "Level" : "Edge")); -#endif /* ACPI_DEBUG */ - +# endif /* ACPI_DEBUG */ #endif /* CONFIG_IA64_IRQ_ACPI */ } @@ -172,10 +168,6 @@ acpi_parse_msapic(acpi_sapic_t *msapic) /* Base address of IPI Message Block */ ipi_base_addr = (unsigned long) ioremap(msapic->interrupt_block, 0); -#ifdef CONFIG_SMP - memset(&smp, -1, sizeof(smp)); -#endif - p = (char *) (msapic + 1); end = p + (msapic->header.length - sizeof(acpi_sapic_t)); @@ -248,6 +240,10 @@ acpi_parse(acpi_rsdp_t *rsdp) printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id, rsdt->header.oem_revision >> 16, rsdt->header.oem_revision & 0xffff); +#ifdef CONFIG_ACPI_KERNEL_CONFIG + acpi_cf_init(rsdp); +#endif + tables = (rsdt->header.length - sizeof(acpi_desc_table_hdr_t)) / 8; for (i = 0; i < tables; i++) { hdrp = (acpi_desc_table_hdr_t *) __va(rsdt->entry_ptrs[i]); @@ -259,12 +255,16 @@ acpi_parse(acpi_rsdp_t *rsdp) acpi_parse_msapic((acpi_sapic_t *) hdrp); } +#ifdef CONFIG_ACPI_KERNEL_CONFIG + acpi_cf_terminate(); +#endif + #ifdef CONFIG_SMP if (available_cpus == 0) { printk("ACPI: Found 0 CPUS; assuming 1\n"); available_cpus = 1; /* We've got at least one of these, no? */ } - smp.cpu_count = available_cpus; + smp_boot_data.cpu_count = available_cpus; #endif return 1; } @@ -278,7 +278,7 @@ acpi_get_sysname (void) #else # if defined (CONFIG_IA64_HP_SIM) return "hpsim"; -# elif defined (CONFIG_IA64_SGI_SN1_SIM) +# elif defined (CONFIG_IA64_SGI_SN1) return "sn1"; # elif defined (CONFIG_IA64_DIG) return "dig"; @@ -286,4 +286,4 @@ acpi_get_sysname (void) # error Unknown platform. Fix acpi.c. # endif #endif -} +} diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 32d83ae75..759db7f52 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -18,6 +18,7 @@ * Goutham Rao: <goutham.rao@intel.com> * Skip non-WB memory and ignore empty memory ranges. */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> @@ -216,12 +217,41 @@ efi_map_pal_code (void) md->phys_addr); continue; } - mask = ~((1 << _PAGE_SIZE_4M)-1); /* XXX should be dynamic? */ + /* + * We must use the same page size as the one used + * for the kernel region when we map the PAL code. + * This way, we avoid overlapping TRs if code is + * executed nearby. The Alt I-TLB installs 256MB + * page sizes as defined for region 7. + * + * XXX Fixme: should be dynamic here (for page size) + */ + mask = ~((1 << _PAGE_SIZE_256M)-1); vaddr = PAGE_OFFSET + md->phys_addr; - printk(__FUNCTION__": mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n", - md->phys_addr, md->phys_addr + (md->num_pages << 12), - vaddr & mask, (vaddr & mask) + 4*1024*1024); + /* + * We must check that the PAL mapping won't overlap + * with the kernel mapping on ITR1. + * + * PAL code is guaranteed to be aligned on a power of 2 + * between 4k and 256KB. + * Also from the documentation, it seems like there is an + * implicit guarantee that you will need only ONE ITR to + * map it. This implies that the PAL code is always aligned + * on its size, i.e., the closest matching page size supported + * by the TLB. Therefore PAL code is guaranteed never to cross + * a 256MB unless it is bigger than 256MB (very unlikely!). + * So for now the following test is enough to determine whether + * or not we need a dedicated ITR for the PAL code. + */ + if ((vaddr & mask) == (PAGE_OFFSET & mask)) { + printk(__FUNCTION__ " : no need to install ITR for PAL Code\n"); + continue; + } + + printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n", + smp_processor_id(), md->phys_addr, md->phys_addr + (md->num_pages << 12), + vaddr & mask, (vaddr & mask) + 256*1024*1024); /* * Cannot write to CRx with PSR.ic=1 @@ -232,12 +262,11 @@ efi_map_pal_code (void) * ITR0/DTR0: used for kernel code/data * ITR1/DTR1: used by HP simulator * ITR2/DTR2: map PAL code - * ITR3/DTR3: used to map PAL calls buffer */ ia64_itr(0x1, 2, vaddr & mask, pte_val(mk_pte_phys(md->phys_addr, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX))), - _PAGE_SIZE_4M); + _PAGE_SIZE_256M); local_irq_restore(flags); ia64_srlz_i (); } @@ -348,6 +377,16 @@ efi_init (void) #endif efi_map_pal_code(); + +#ifndef CONFIG_IA64_SOFTSDV_HACKS + /* + * (Some) SoftSDVs seem to have a problem with this call. + * Since it's mostly a performance optimization, just don't do + * it for now... --davidm 99/12/6 + */ + efi_enter_virtual_mode(); +#endif + } void diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index eba75378e..ffb1760ea 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -120,6 +120,9 @@ GLOBAL_ENTRY(ia64_switch_to) mov r13=in0 // set "current" pointer ;; DO_LOAD_SWITCH_STACK( ) +#ifdef CONFIG_SMP + sync.i // ensure "fc"s done by this CPU are visible on other CPUs +#endif br.ret.sptk.few rp END(ia64_switch_to) @@ -1088,7 +1091,7 @@ sys_call_table: data8 sys_setpriority data8 sys_statfs data8 sys_fstatfs - data8 sys_ioperm // 1105 + data8 ia64_ni_syscall data8 sys_semget data8 sys_semop data8 sys_semctl diff --git a/arch/ia64/kernel/fw-emu.c b/arch/ia64/kernel/fw-emu.c index c34bbaeee..34316fe58 100644 --- a/arch/ia64/kernel/fw-emu.c +++ b/arch/ia64/kernel/fw-emu.c @@ -20,7 +20,7 @@ #define MB (1024*1024UL) -#define NUM_MEM_DESCS 3 +#define NUM_MEM_DESCS 2 static char fw_mem[( sizeof(efi_system_table_t) + sizeof(efi_runtime_services_t) @@ -453,6 +453,12 @@ sys_fw_init (const char *args, int arglen) md->num_pages = (1*MB) >> 12; /* 1MB (in 4KB pages) */ md->attribute = EFI_MEMORY_WB; +#if 0 + /* + * XXX bootmem is broken for now... (remember to NUM_MEM_DESCS + * if you re-enable this!) + */ + /* descriptor for high memory (>4GB): */ md = &efi_memmap[2]; md->type = EFI_CONVENTIONAL_MEMORY; @@ -461,6 +467,7 @@ sys_fw_init (const char *args, int arglen) md->virt_addr = 0; md->num_pages = (32*MB) >> 12; /* 32MB (in 4KB pages) */ md->attribute = EFI_MEMORY_WB; +#endif bp = id(ZERO_PAGE_ADDR); bp->efi_systab = __pa(&fw_mem); diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index bea14236d..e6298b297 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S @@ -111,7 +111,7 @@ GLOBAL_ENTRY(_start) * be implemented more efficiently (for example, __switch_to() * always sets the psr.dfh bit of the task it is switching to). */ - addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 + addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE-16,r2 addl r2=IA64_RBS_OFFSET,r2 // initialize the RSE mov ar.rsc=r0 // place RSE in enforced lazy mode ;; diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c index 62e792612..d3d2416cf 100644 --- a/arch/ia64/kernel/ia64_ksyms.c +++ b/arch/ia64/kernel/ia64_ksyms.c @@ -10,6 +10,7 @@ EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(memscan); EXPORT_SYMBOL(strcat); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strcmp); @@ -18,6 +19,8 @@ EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strtok); @@ -27,24 +30,58 @@ EXPORT_SYMBOL(pci_free_consistent); #include <linux/in6.h> #include <asm/checksum.h> +/* not coded yet?? EXPORT_SYMBOL(csum_ipv6_magic); */ EXPORT_SYMBOL(csum_partial_copy_nocheck); +EXPORT_SYMBOL(csum_tcpudp_magic); +EXPORT_SYMBOL(ip_compute_csum); +EXPORT_SYMBOL(ip_fast_csum); + +#include <asm/io.h> +EXPORT_SYMBOL(__ia64_memcpy_fromio); +EXPORT_SYMBOL(__ia64_memcpy_toio); +EXPORT_SYMBOL(__ia64_memset_c_io); #include <asm/irq.h> EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); + +#include <asm/page.h> +EXPORT_SYMBOL(clear_page); + +#include <asm/pci.h> +EXPORT_SYMBOL(pci_dma_sync_sg); +EXPORT_SYMBOL(pci_dma_sync_single); +EXPORT_SYMBOL(pci_map_sg); +EXPORT_SYMBOL(pci_map_single); +EXPORT_SYMBOL(pci_unmap_sg); +EXPORT_SYMBOL(pci_unmap_single); #include <asm/processor.h> EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(kernel_thread); +#include <asm/system.h> +#ifdef CONFIG_IA64_DEBUG_IRQ +EXPORT_SYMBOL(last_cli_ip); +#endif + #ifdef CONFIG_SMP + +#include <asm/current.h> #include <asm/hardirq.h> EXPORT_SYMBOL(synchronize_irq); +#include <asm/smp.h> +EXPORT_SYMBOL(smp_call_function); + +#include <linux/smp.h> +EXPORT_SYMBOL(smp_num_cpus); + #include <asm/smplock.h> EXPORT_SYMBOL(kernel_flag); -#include <asm/system.h> +/* #include <asm/system.h> */ EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_save_flags); @@ -54,17 +91,29 @@ EXPORT_SYMBOL(__global_restore_flags); #include <asm/uaccess.h> EXPORT_SYMBOL(__copy_user); +EXPORT_SYMBOL(__do_clear_user); #include <asm/unistd.h> EXPORT_SYMBOL(__ia64_syscall); /* from arch/ia64/lib */ +extern void __divsi3(void); +extern void __udivsi3(void); +extern void __modsi3(void); +extern void __umodsi3(void); extern void __divdi3(void); extern void __udivdi3(void); extern void __moddi3(void); extern void __umoddi3(void); +EXPORT_SYMBOL_NOVERS(__divsi3); +EXPORT_SYMBOL_NOVERS(__udivsi3); +EXPORT_SYMBOL_NOVERS(__modsi3); +EXPORT_SYMBOL_NOVERS(__umodsi3); EXPORT_SYMBOL_NOVERS(__divdi3); EXPORT_SYMBOL_NOVERS(__udivdi3); EXPORT_SYMBOL_NOVERS(__moddi3); EXPORT_SYMBOL_NOVERS(__umoddi3); + +extern unsigned long ia64_iobase; +EXPORT_SYMBOL(ia64_iobase); diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index c913fdc3d..30d4def40 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -536,8 +536,7 @@ void enable_irq(unsigned int irq) desc->depth--; break; case 0: - printk("enable_irq() unbalanced from %p\n", - __builtin_return_address(0)); + printk("enable_irq() unbalanced from %p\n", (void *) __builtin_return_address(0)); } spin_unlock_irqrestore(&desc->lock, flags); } diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index fe686db0e..2166e205f 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -39,7 +39,8 @@ spinlock_t ivr_read_lock; #endif -unsigned long ipi_base_addr = IPI_DEFAULT_BASE_ADDR; /* default base addr of IPI table */ +/* default base addr of IPI table */ +unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IPI_DEFAULT_BASE_ADDR); /* * Legacy IRQ to IA-64 vector translation table. Any vector not in @@ -220,13 +221,23 @@ ipi_send (int cpu, int vector, int delivery_mode, int redirect) { unsigned long ipi_addr; unsigned long ipi_data; + unsigned long phys_cpu_id; #ifdef CONFIG_ITANIUM_A1_SPECIFIC unsigned long flags; #endif -# define EID 0 + +#ifdef CONFIG_SMP + phys_cpu_id = cpu_physical_id(cpu); +#else + phys_cpu_id = (ia64_get_lid() >> 16) & 0xffff; +#endif + + /* + * cpu number is in 8bit ID and 8bit EID + */ ipi_data = (delivery_mode << 8) | (vector & 0xff); - ipi_addr = ipi_base_addr | ((cpu << 8 | EID) << 4) | ((redirect & 1) << 3); + ipi_addr = ipi_base_addr | (phys_cpu_id << 4) | ((redirect & 1) << 3); #ifdef CONFIG_ITANIUM_A1_SPECIFIC spin_lock_irqsave(&ivr_read_lock, flags); diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index d1b599f77..fa0ad0993 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S @@ -4,6 +4,8 @@ * Copyright (C) 1998-2000 Hewlett-Packard Co * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> * Copyright (C) 1998-2000 David Mosberger <davidm@hpl.hp.com> + * + * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> TLB handling for SMP */ /* * This file defines the interrupt vector table used by the CPU. @@ -134,32 +136,51 @@ ia64_ivt: (p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL? dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry ;; -(p7) ld8 r17=[r17] // fetch the L2 entry (may be 0) +(p7) ld8 r20=[r17] // fetch the L2 entry (may be 0) shr.u r19=r16,PAGE_SHIFT // shift L3 index into position ;; -(p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? - dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry +(p7) cmp.eq.or.andcm p6,p7=r20,r0 // was L2 entry NULL? + dep r21=r19,r20,3,(PAGE_SHIFT-3) // compute address of L3 page table entry ;; -(p7) ld8 r18=[r17] // read the L3 PTE +(p7) ld8 r18=[r21] // read the L3 PTE mov r19=cr.isr // cr.isr bit 0 tells us if this is an insn miss ;; (p7) tbit.z p6,p7=r18,0 // page present bit cleared? - mov r21=cr.iha // get the VHPT address that caused the TLB miss + mov r22=cr.iha // get the VHPT address that caused the TLB miss ;; // avoid RAW on p7 (p7) tbit.nz.unc p10,p11=r19,32 // is it an instruction TLB miss? - dep r17=0,r17,0,PAGE_SHIFT // clear low bits to get page address + dep r23=0,r20,0,PAGE_SHIFT // clear low bits to get page address ;; (p10) itc.i r18 // insert the instruction TLB entry (p11) itc.d r18 // insert the data TLB entry (p6) br.spnt.few page_fault // handle bad address/page not present (page fault) - mov cr.ifa=r21 + mov cr.ifa=r22 // Now compute and insert the TLB entry for the virtual page table. // We never execute in a page table page so there is no need to set // the exception deferral bit. - adds r16=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r17 + adds r24=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r23 + ;; +(p7) itc.d r24 + ;; +#ifdef CONFIG_SMP + // + // Re-check L2 and L3 pagetable. If they changed, we may have received + // a ptc.g between reading the pagetable and the "itc". If so, + // flush the entry we inserted and retry. + // + ld8 r25=[r21] // read L3 PTE again + ld8 r26=[r17] // read L2 entry again + ;; + cmp.ne p6,p7=r26,r20 // did L2 entry change + mov r27=PAGE_SHIFT<<2 + ;; +(p6) ptc.l r22,r27 // purge PTE page translation +(p7) cmp.ne.or.andcm p6,p7=r25,r18 // did L3 PTE change ;; -(p7) itc.d r16 +(p6) ptc.l r16,r27 // purge translation +#endif + mov pr=r31,-1 // restore predicate registers rfi @@ -175,22 +196,32 @@ ia64_ivt: * The speculative access will fail if there is no TLB entry * for the L3 page table page we're trying to access. */ - mov r16=cr.iha // get virtual address of L3 PTE + mov r16=cr.ifa // get virtual address + mov r19=cr.iha // get virtual address of L3 PTE ;; - ld8.s r16=[r16] // try to read L3 PTE + ld8.s r17=[r19] // try to read L3 PTE mov r31=pr // save predicates ;; - tnat.nz p6,p0=r16 // did read succeed? + tnat.nz p6,p0=r17 // did read succeed? (p6) br.cond.spnt.many 1f ;; - itc.i r16 + itc.i r17 + ;; +#ifdef CONFIG_SMP + ld8.s r18=[r19] // try to read L3 PTE again and see if same + mov r20=PAGE_SHIFT<<2 // setup page size for purge ;; + cmp.eq p6,p7=r17,r18 + ;; +(p7) ptc.l r16,r20 +#endif mov pr=r31,-1 rfi -1: mov r16=cr.ifa // get address that caused the TLB miss - ;; - rsm psr.dt // use physical addressing for data +#ifdef CONFIG_DISABLE_VHPT +itlb_fault: +#endif +1: 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 @@ -228,6 +259,15 @@ ia64_ivt: (p7) itc.i r18 // insert the instruction TLB entry (p6) br.spnt.few page_fault // handle bad address/page not present (page fault) ;; +#ifdef CONFIG_SMP + ld8 r19=[r17] // re-read the PTE and check if same + ;; + cmp.eq p6,p7=r18,r19 + mov r20=PAGE_SHIFT<<2 + ;; +(p7) ptc.l r16,r20 // PTE changed purge translation +#endif + mov pr=r31,-1 // restore predicate registers rfi @@ -243,22 +283,32 @@ ia64_ivt: * The speculative access will fail if there is no TLB entry * for the L3 page table page we're trying to access. */ - mov r16=cr.iha // get virtual address of L3 PTE + mov r16=cr.ifa // get virtual address + mov r19=cr.iha // get virtual address of L3 PTE ;; - ld8.s r16=[r16] // try to read L3 PTE + ld8.s r17=[r19] // try to read L3 PTE mov r31=pr // save predicates ;; - tnat.nz p6,p0=r16 // did read succeed? + tnat.nz p6,p0=r17 // did read succeed? (p6) br.cond.spnt.many 1f ;; - itc.d r16 + itc.d r17 + ;; +#ifdef CONFIG_SMP + ld8.s r18=[r19] // try to read L3 PTE again and see if same + mov r20=PAGE_SHIFT<<2 // setup page size for purge ;; + cmp.eq p6,p7=r17,r18 + ;; +(p7) ptc.l r16,r20 +#endif mov pr=r31,-1 rfi -1: mov r16=cr.ifa // get address that caused the TLB miss - ;; - rsm psr.dt // use physical addressing for data +#ifdef CONFIG_DISABLE_VHPT +dtlb_fault: +#endif +1: 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 @@ -296,6 +346,14 @@ ia64_ivt: (p7) itc.d r18 // insert the instruction TLB entry (p6) br.spnt.few page_fault // handle bad address/page not present (page fault) ;; +#ifdef CONFIG_SMP + ld8 r19=[r17] // re-read the PTE and check if same + ;; + cmp.eq p6,p7=r18,r19 + mov r20=PAGE_SHIFT<<2 + ;; +(p7) ptc.l r16,r20 // PTE changed purge translation +#endif mov pr=r31,-1 // restore predicate registers rfi @@ -303,6 +361,16 @@ ia64_ivt: ///////////////////////////////////////////////////////////////////////////////////////// // 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19) mov r16=cr.ifa // get address that caused the TLB miss +#ifdef CONFIG_DISABLE_VHPT + mov r31=pr + ;; + shr.u r21=r16,61 // get the region number into r21 + ;; + cmp.gt p6,p0=6,r21 // user mode +(p6) br.cond.dptk.many itlb_fault + ;; + mov pr=r31,-1 +#endif movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX ;; shr.u r18=r16,57 // move address bit 61 to bit 4 @@ -323,8 +391,14 @@ ia64_ivt: movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW mov r20=cr.isr mov r21=cr.ipsr - mov r19=pr + mov r31=pr + ;; +#ifdef CONFIG_DISABLE_VHPT + shr.u r22=r16,61 // get the region number into r21 ;; + cmp.gt p8,p0=6,r22 // user mode +(p8) br.cond.dptk.many dtlb_fault +#endif tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? shr.u r18=r16,57 // move address bit 61 to bit 4 dep r16=0,r16,IA64_MAX_PHYS_BITS,(64-IA64_MAX_PHYS_BITS) // clear ed & reserved bits @@ -337,7 +411,7 @@ ia64_ivt: (p6) mov cr.ipsr=r21 ;; (p7) itc.d r16 // insert the TLB entry - mov pr=r19,-1 + mov pr=r31,-1 rfi ;; @@ -452,6 +526,7 @@ page_fault: // a nested TLB miss hit where we look up the physical address of the L3 PTE // and then continue at label 1 below. // +#ifndef CONFIG_SMP mov r16=cr.ifa // get the address that caused the fault movl r30=1f // load continuation point in case of nested fault ;; @@ -465,6 +540,36 @@ page_fault: ;; st8 [r17]=r18 // store back updated PTE itc.d r18 // install updated PTE +#else + mov r16=cr.ifa // get the address that caused the fault + movl r30=1f // load continuation point in case of nested fault + ;; + thash r17=r16 // compute virtual address of L3 PTE + mov r28=ar.ccv // save ar.ccv + mov r29=b0 // save b0 in case of nested fault + mov r27=pr + ;; +1: ld8 r18=[r17] + ;; // avoid RAW on r18 + mov ar.ccv=r18 // set compare value for cmpxchg + or r25=_PAGE_D,r18 // set the dirty bit + ;; + cmpxchg8.acq r26=[r17],r25,ar.ccv + mov r24=PAGE_SHIFT<<2 + ;; + cmp.eq p6,p7=r26,r18 + ;; +(p6) itc.d r25 // install updated PTE + ;; + ld8 r18=[r17] // read PTE again + ;; + cmp.eq p6,p7=r18,r25 // is it same as the newly installed + ;; +(p7) ptc.l r16,r24 + mov b0=r29 // restore b0 + mov ar.ccv=r28 + mov pr=r27,-1 +#endif rfi .align 1024 @@ -486,6 +591,8 @@ page_fault: (p6) mov r16=r18 // if so, use cr.iip instead of cr.ifa mov pr=r31,-1 #endif /* CONFIG_ITANIUM */ + +#ifndef CONFIG_SMP movl r30=1f // load continuation point in case of nested fault ;; thash r17=r16 // compute virtual address of L3 PTE @@ -515,12 +622,58 @@ page_fault: ;; st8 [r17]=r18 // store back updated PTE itc.i r18 // install updated PTE +#else + movl r30=1f // load continuation point in case of nested fault + ;; + thash r17=r16 // compute virtual address of L3 PTE + mov r28=ar.ccv // save ar.ccv + mov r29=b0 // save b0 in case of nested fault) + mov r27=pr + ;; +1: ld8 r18=[r17] +#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. + // + ;; + tbit.nz p6,p0=r18,0 // page present bit set? +(p6) br.cond.sptk 1f + ;; // avoid WAW on p6 + mov pr=r27,-1 + br.cond.sptk page_fault // page wasn't present +1: +#else + ;; // avoid RAW on r18 +#endif + mov ar.ccv=r18 // set compare value for cmpxchg + or r25=_PAGE_A,r18 // set the accessed bit + ;; + cmpxchg8.acq r26=[r17],r25,ar.ccv + mov r24=PAGE_SHIFT<<2 + ;; + cmp.eq p6,p7=r26,r18 + ;; +(p6) itc.i r25 // install updated PTE + ;; + ld8 r18=[r17] // read PTE again + ;; + cmp.eq p6,p7=r18,r25 // is it same as the newly installed + ;; +(p7) ptc.l r16,r24 + mov b0=r29 // restore b0 + mov ar.ccv=r28 + mov pr=r27,-1 +#endif rfi .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55) // Like Entry 8, except for data access +#ifndef CONFIG_SMP mov r16=cr.ifa // get the address that caused the fault movl r30=1f // load continuation point in case of nested fault ;; @@ -534,6 +687,36 @@ page_fault: ;; st8 [r17]=r18 // store back updated PTE itc.d r18 // install updated PTE +#else + mov r16=cr.ifa // get the address that caused the fault + movl r30=1f // load continuation point in case of nested fault + ;; + thash r17=r16 // compute virtual address of L3 PTE + mov r28=ar.ccv // save ar.ccv + mov r29=b0 // save b0 in case of nested fault + mov r27=pr + ;; +1: ld8 r18=[r17] + ;; // avoid RAW on r18 + mov ar.ccv=r18 // set compare value for cmpxchg + or r25=_PAGE_A,r18 // set the dirty bit + ;; + cmpxchg8.acq r26=[r17],r25,ar.ccv + mov r24=PAGE_SHIFT<<2 + ;; + cmp.eq p6,p7=r26,r18 + ;; +(p6) itc.d r25 // install updated PTE + ;; + ld8 r18=[r17] // read PTE again + ;; + cmp.eq p6,p7=r18,r25 // is it same as the newly installed + ;; +(p7) ptc.l r16,r24 + mov b0=r29 // restore b0 + mov ar.ccv=r28 + mov pr=r27,-1 +#endif rfi .align 1024 diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index b57d4702d..333258d35 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -43,10 +43,6 @@ u64 ia64_mca_stackframe[32]; u64 ia64_mca_bspstore[1024]; u64 ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16))); -#if defined(SAL_MPINIT_WORKAROUND) && !defined(CONFIG_SMP) -int bootstrap_processor = -1; -#endif - static void ia64_mca_cmc_vector_setup(int enable, int_vector_t cmc_vector); static void ia64_mca_wakeup_ipi_wait(void); @@ -223,12 +219,6 @@ ia64_mca_init(void) IA64_MCA_DEBUG("ia64_mca_init : begin\n"); -#if defined(SAL_MPINIT_WORKAROUND) && !defined(CONFIG_SMP) - /* XXX -- workaround for SAL bug for running on MP system, but UP kernel */ - - bootstrap_processor = hard_smp_processor_id(); -#endif - /* Clear the Rendez checkin flag for all cpus */ for(i = 0 ; i < IA64_MAXCPUS; i++) ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; @@ -265,8 +255,11 @@ ia64_mca_init(void) IA64_MCA_DEBUG("ia64_mca_init : correctable mca vector setup done\n"); ia64_mc_info.imi_mca_handler = __pa(ia64_os_mca_dispatch); - ia64_mc_info.imi_mca_handler_size = - __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch); + /* + * XXX - disable SAL checksum by setting size to 0; should be + * __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch); + */ + ia64_mc_info.imi_mca_handler_size = 0; /* Register the os mca handler with SAL */ if (ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, ia64_mc_info.imi_mca_handler, @@ -278,10 +271,14 @@ ia64_mca_init(void) IA64_MCA_DEBUG("ia64_mca_init : registered os mca handler with SAL\n"); + /* + * XXX - disable SAL checksum by setting size to 0, should be + * IA64_INIT_HANDLER_SIZE + */ ia64_mc_info.imi_monarch_init_handler = __pa(mon_init_ptr->fp); - ia64_mc_info.imi_monarch_init_handler_size = IA64_INIT_HANDLER_SIZE; + ia64_mc_info.imi_monarch_init_handler_size = 0; ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp); - ia64_mc_info.imi_slave_init_handler_size = IA64_INIT_HANDLER_SIZE; + ia64_mc_info.imi_slave_init_handler_size = 0; IA64_MCA_DEBUG("ia64_mca_init : os init handler at %lx\n",ia64_mc_info.imi_monarch_init_handler); @@ -386,7 +383,7 @@ ia64_mca_wakeup_all(void) int cpu; /* Clear the Rendez checkin flag for all cpus */ - for(cpu = 0 ; cpu < IA64_MAXCPUS; cpu++) + for(cpu = 0 ; cpu < smp_num_cpus; cpu++) if (ia64_mc_info.imi_rendez_checkin[cpu] == IA64_MCA_RENDEZ_CHECKIN_DONE) ia64_mca_wakeup(cpu); @@ -404,11 +401,14 @@ ia64_mca_wakeup_all(void) void ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) { - int flags; + int flags, cpu = 0; /* Mask all interrupts */ save_and_cli(flags); - ia64_mc_info.imi_rendez_checkin[ia64_get_cpuid(0)] = IA64_MCA_RENDEZ_CHECKIN_DONE; +#ifdef CONFIG_SMP + cpu = cpu_logical_id(hard_smp_processor_id()); +#endif + ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE; /* Register with the SAL monarch that the slave has * reached SAL */ diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S index 6b714108e..15993525d 100644 --- a/arch/ia64/kernel/mca_asm.S +++ b/arch/ia64/kernel/mca_asm.S @@ -6,6 +6,8 @@ // 00/03/29 cfleck Added code to save INIT handoff state in pt_regs format, switch to temp kstack, // switch modes, jump to C INIT handler // +#include <linux/config.h> + #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/mca_asm.h> @@ -680,32 +682,22 @@ end_os_mca_restore: .proc ia64_monarch_init_handler ia64_monarch_init_handler: -#if defined(SAL_MPINIT_WORKAROUND) +#if defined(CONFIG_SMP) && defined(SAL_MPINIT_WORKAROUND) // // work around SAL bug that sends all processors to monarch entry // - .global bootstrap_processor - - movl r21=24 - movl r20=16 mov r17=cr.lid - movl r18=bootstrap_processor + movl r18=__cpu_physical_id ;; - dep r18=0,r18,61,3 // convert bsp to physical address + dep r18=0,r18,61,3 // convert to physical address ;; - shr r19=r17,r20 - shr r22=r17,r21 + shr.u r17=r17,16 ld4 r18=[r18] // get the BSP ID ;; - and r19=0xf, r19 - and r22=0xf, r22 - ;; - shl r19=r19,8 // get them in the right order - ;; - or r22=r22,r19 // combine EID and LID + dep r17=0,r17,16,48 ;; - cmp.eq p6,p7=r22,r18 // Am I the BSP ? -(p7) br.cond.spnt slave_init_spin_me + cmp4.ne p6,p0=r17,r18 // Am I the BSP ? +(p6) br.cond.spnt slave_init_spin_me ;; #endif diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h index 24be2f53d..8790d49c3 100644 --- a/arch/ia64/kernel/minstate.h +++ b/arch/ia64/kernel/minstate.h @@ -192,13 +192,3 @@ #define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS #define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS #define SAVE_MIN DO_SAVE_MIN(mov rCRIFS=r0,) STOPS - -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC -# define STOPS nop.i 0x0;; nop.i 0x0;; nop.i 0x0;; -#else -# define STOPS -#endif - -#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS -#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS -#define SAVE_MIN DO_SAVE_MIN(mov rCRIFS=r0,) STOPS diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S index 0b07163dc..2e56a428e 100644 --- a/arch/ia64/kernel/pal.S +++ b/arch/ia64/kernel/pal.S @@ -54,7 +54,8 @@ END(ia64_pal_default_handler) * * in0 Pointer to struct ia64_pal_retval * in1 Index of PAL service - * in2 - in4 Remaning PAL arguments + * in2 - in4 Remaining PAL arguments + * in5 1 ==> clear psr.ic, 0 ==> don't clear psr.ic * */ GLOBAL_ENTRY(ia64_pal_call_static) @@ -68,18 +69,22 @@ GLOBAL_ENTRY(ia64_pal_call_static) } ;; ld8 loc2 = [loc2] // loc2 <- entry point - mov r30 = in2 - mov r31 = in3 + tbit.nz p6,p7 = in5, 0 + adds r8 = 1f-1b,r8 ;; mov loc3 = psr mov loc0 = rp UNW(.body) - adds r8 = 1f-1b,r8 - ;; - rsm psr.i + mov r30 = in2 + +(p6) rsm psr.i | psr.ic + mov r31 = in3 mov b7 = loc2 + +(p7) rsm psr.i + ;; +(p6) srlz.i mov rp = r8 - ;; br.cond.sptk.few b7 1: mov psr.l = loc3 mov ar.pfs = loc1 diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c index ecd7b0886..de71a2d22 100644 --- a/arch/ia64/kernel/palinfo.c +++ b/arch/ia64/kernel/palinfo.c @@ -10,11 +10,11 @@ * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com> * * 05/26/2000 S.Eranian initial release + * 08/21/2000 S.Eranian updated to July 2000 PAL specs * * ISSUES: - * - because of some PAL bugs, some calls return invalid results or - * are empty for now. - * - remove hack to avoid problem with <= 256M RAM for itr. + * - as of 2.2.9/2.2.12, the following values are still wrong + * PAL_VM_SUMMARY: key & rid sizes */ #include <linux/config.h> #include <linux/types.h> @@ -111,7 +111,7 @@ static const char *rse_hints[]={ #define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *)) /* - * The current revision of the Volume 2 of + * The current revision of the Volume 2 (July 2000) of * IA-64 Architecture Software Developer's Manual is wrong. * Table 4-10 has invalid information concerning the ma field: * Correct table is: @@ -132,38 +132,6 @@ static const char *mem_attrib[]={ "NaTPage" /* 111 */ }; - - -/* - * Allocate a buffer suitable for calling PAL code in Virtual mode - * - * The documentation (PAL2.6) allows DTLB misses on the buffer. So - * using the TC is enough, no need to pin the entry. - * - * We allocate a kernel-sized page (at least 4KB). This is enough to - * hold any possible reply. - */ -static inline void * -get_palcall_buffer(void) -{ - void *tmp; - - tmp = (void *)__get_free_page(GFP_KERNEL); - if (tmp == 0) { - printk(KERN_ERR __FUNCTION__" : can't get a buffer page\n"); - } - return tmp; -} - -/* - * Free a palcall buffer allocated with the previous call - */ -static inline void -free_palcall_buffer(void *addr) -{ - __free_page(addr); -} - /* * Take a 64bit vector and produces a string such that * if bit n is set then 2^n in clear text is generated. The adjustment @@ -243,17 +211,12 @@ power_info(char *page) { s64 status; char *p = page; - pal_power_mgmt_info_u_t *halt_info; + u64 halt_info_buffer[8]; + pal_power_mgmt_info_u_t *halt_info =(pal_power_mgmt_info_u_t *)halt_info_buffer; int i; - halt_info = get_palcall_buffer(); - if (halt_info == 0) return 0; - status = ia64_pal_halt_info(halt_info); - if (status != 0) { - free_palcall_buffer(halt_info); - return 0; - } + if (status != 0) return 0; for (i=0; i < 8 ; i++ ) { if (halt_info[i].pal_power_mgmt_info_s.im == 1) { @@ -270,9 +233,6 @@ power_info(char *page) p += sprintf(p,"Power level %d: not implemented\n",i); } } - - free_palcall_buffer(halt_info); - return p - page; } @@ -502,7 +462,7 @@ register_info(char *page) "RSE load/store hints : %ld (%s)\n", phys_stacked, hints.ph_data, - hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)"); + hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)"); if (ia64_pal_debug_info(&iregs, &dregs)) return 0; @@ -569,7 +529,9 @@ static const char *bus_features[]={ "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, + NULL, NULL, NULL, NULL, + "Enable Cache Line Repl. Exclusive", + "Enable Cache Line Repl. Shared", "Disable Transaction Queuing", "Disable Reponse Error Checking", "Disable Bus Error Checking", @@ -673,16 +635,10 @@ static int perfmon_info(char *page) { char *p = page; - u64 *pm_buffer; + u64 pm_buffer[16]; pal_perf_mon_info_u_t pm_info; - pm_buffer = (u64 *)get_palcall_buffer(); - if (pm_buffer == 0) return 0; - - if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) { - free_palcall_buffer(pm_buffer); - return 0; - } + if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0; #ifdef IA64_PAL_PERF_MON_INFO_BUG /* @@ -719,8 +675,6 @@ perfmon_info(char *page) p += sprintf(p, "\n"); - free_palcall_buffer(pm_buffer); - return p - page; } diff --git a/arch/ia64/kernel/pci-dma.c b/arch/ia64/kernel/pci-dma.c index 80509c6a1..6293cdfa0 100644 --- a/arch/ia64/kernel/pci-dma.c +++ b/arch/ia64/kernel/pci-dma.c @@ -97,7 +97,8 @@ setup_swiotlb (void) io_tlb_index = 0; io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *)); - printk("Placing software IO TLB between 0x%p - 0x%p\n", io_tlb_start, io_tlb_end); + printk("Placing software IO TLB between 0x%p - 0x%p\n", + (void *) io_tlb_start, (void *) io_tlb_end); } /* @@ -394,7 +395,7 @@ pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int * 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 +dma_addr_t pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction) { if (direction == PCI_DMA_NONE) @@ -410,7 +411,7 @@ pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction) * After this call, reads by the cpu to the buffer are guarenteed to see * whatever the device wrote there. */ -extern inline void +void pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) { if (direction == PCI_DMA_NONE) @@ -433,7 +434,7 @@ pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int d * Device ownership issues as mentioned above for pci_map_single are * the same here. */ -extern inline int +int pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { if (direction == PCI_DMA_NONE) @@ -446,7 +447,7 @@ pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direct * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -extern inline void +void pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { if (direction == PCI_DMA_NONE) @@ -463,7 +464,7 @@ pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int dire * next point you give the PCI dma address back to the card, the * device again owns the buffer. */ -extern inline void +void pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) { if (direction == PCI_DMA_NONE) @@ -478,7 +479,7 @@ pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, * The same as pci_dma_sync_single but for a scatter-gather list, * same rules and usage. */ -extern inline void +void pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) { if (direction == PCI_DMA_NONE) diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 752b2a9a1..e5efbc8b5 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -10,15 +10,19 @@ #include <linux/config.h> #include <linux/kernel.h> +#include <linux/init.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/smp_lock.h> +#include <linux/proc_fs.h> +#include <linux/ptrace.h> #include <asm/errno.h> #include <asm/hw_irq.h> #include <asm/processor.h> #include <asm/system.h> #include <asm/uaccess.h> +#include <asm/pal.h> /* Long blurb on how this works: * We set dcr.pp, psr.pp, and the appropriate pmc control values with @@ -52,68 +56,107 @@ #ifdef CONFIG_PERFMON #define MAX_PERF_COUNTER 4 /* true for Itanium, at least */ +#define PMU_FIRST_COUNTER 4 /* first generic counter */ + #define WRITE_PMCS_AND_START 0xa0 #define WRITE_PMCS 0xa1 #define READ_PMDS 0xa2 #define STOP_PMCS 0xa3 -#define IA64_COUNTER_MASK 0xffffffffffffff6fL -#define PERF_OVFL_VAL 0xffffffffL -volatile int used_by_system; -struct perfmon_counter { - unsigned long data; - unsigned long counter_num; -}; +/* + * this structure needs to be enhanced + */ +typedef struct { + unsigned long pmu_reg_data; /* generic PMD register */ + unsigned long pmu_reg_num; /* which register number */ +} perfmon_reg_t; + +/* + * This structure is initialize at boot time and contains + * a description of the PMU main characteristic as indicated + * by PAL + */ +typedef struct { + unsigned long perf_ovfl_val; /* overflow value for generic counters */ + unsigned long max_pmc; /* highest PMC */ + unsigned long max_pmd; /* highest PMD */ + unsigned long max_counters; /* number of generic counter pairs (PMC/PMD) */ +} pmu_config_t; + +/* XXX will go static when ptrace() is cleaned */ +unsigned long perf_ovfl_val; /* overflow value for generic counters */ + +static pmu_config_t pmu_conf; +/* + * could optimize to avoid cache conflicts in SMP + */ unsigned long pmds[NR_CPUS][MAX_PERF_COUNTER]; asmlinkage unsigned long -sys_perfmonctl (int cmd1, int cmd2, void *ptr) +sys_perfmonctl (int cmd, int count, void *ptr, long arg4, long arg5, long arg6, long arg7, long arg8, long stack) { - struct perfmon_counter tmp, *cptr = ptr; - unsigned long cnum, dcr, flags; - struct perf_counter; + struct pt_regs *regs = (struct pt_regs *) &stack; + perfmon_reg_t tmp, *cptr = ptr; + unsigned long cnum; int i; - switch (cmd1) { + switch (cmd) { case WRITE_PMCS: /* Writes to PMC's and clears PMDs */ case WRITE_PMCS_AND_START: /* Also starts counting */ - if (cmd2 <= 0 || cmd2 > MAX_PERF_COUNTER - used_by_system) - return -EINVAL; - - if (!access_ok(VERIFY_READ, cptr, sizeof(struct perf_counter)*cmd2)) + if (!access_ok(VERIFY_READ, cptr, sizeof(struct perfmon_reg_t)*count)) return -EFAULT; - current->thread.flags |= IA64_THREAD_PM_VALID; + for (i = 0; i < count; i++, cptr++) { - for (i = 0; i < cmd2; i++, cptr++) { copy_from_user(&tmp, cptr, sizeof(tmp)); - /* XXX need to check validity of counter_num and perhaps data!! */ - if (tmp.counter_num < 4 - || tmp.counter_num >= 4 + MAX_PERF_COUNTER - used_by_system) - return -EFAULT; - - ia64_set_pmc(tmp.counter_num, tmp.data); - ia64_set_pmd(tmp.counter_num, 0); - pmds[smp_processor_id()][tmp.counter_num - 4] = 0; + + /* XXX need to check validity of pmu_reg_num and perhaps data!! */ + + if (tmp.pmu_reg_num > pmu_conf.max_pmc || tmp.pmu_reg_num == 0) return -EFAULT; + + ia64_set_pmc(tmp.pmu_reg_num, tmp.pmu_reg_data); + + /* to go away */ + if (tmp.pmu_reg_num >= PMU_FIRST_COUNTER && tmp.pmu_reg_num < PMU_FIRST_COUNTER+pmu_conf.max_counters) { + ia64_set_pmd(tmp.pmu_reg_num, 0); + pmds[smp_processor_id()][tmp.pmu_reg_num - PMU_FIRST_COUNTER] = 0; + + printk(__FUNCTION__" setting PMC/PMD[%ld] es=0x%lx pmd[%ld]=%lx\n", tmp.pmu_reg_num, (tmp.pmu_reg_data>>8) & 0x7f, tmp.pmu_reg_num, ia64_get_pmd(tmp.pmu_reg_num)); + } else + printk(__FUNCTION__" setting PMC[%ld]=0x%lx\n", tmp.pmu_reg_num, tmp.pmu_reg_data); } - if (cmd1 == WRITE_PMCS_AND_START) { + if (cmd == WRITE_PMCS_AND_START) { +#if 0 +/* irrelevant with user monitors */ local_irq_save(flags); + dcr = ia64_get_dcr(); dcr |= IA64_DCR_PP; ia64_set_dcr(dcr); + local_irq_restore(flags); +#endif + ia64_set_pmc(0, 0); + + /* will start monitoring right after rfi */ + ia64_psr(regs)->up = 1; } + /* + * mark the state as valid. + * this will trigger save/restore at context switch + */ + current->thread.flags |= IA64_THREAD_PM_VALID; break; case READ_PMDS: - if (cmd2 <= 0 || cmd2 > MAX_PERF_COUNTER - used_by_system) + if (count <= 0 || count > MAX_PERF_COUNTER) return -EINVAL; - if (!access_ok(VERIFY_WRITE, cptr, sizeof(struct perf_counter)*cmd2)) + if (!access_ok(VERIFY_WRITE, cptr, sizeof(struct perfmon_reg_t)*count)) return -EFAULT; /* This looks shady, but IMHO this will work fine. This is @@ -121,14 +164,15 @@ sys_perfmonctl (int cmd1, int cmd2, void *ptr) * with the interrupt handler. See explanation in the * following comment. */ - +#if 0 +/* irrelevant with user monitors */ local_irq_save(flags); __asm__ __volatile__("rsm psr.pp\n"); dcr = ia64_get_dcr(); dcr &= ~IA64_DCR_PP; ia64_set_dcr(dcr); local_irq_restore(flags); - +#endif /* * We cannot write to pmc[0] to stop counting here, as * that particular instruction might cause an overflow @@ -142,36 +186,47 @@ sys_perfmonctl (int cmd1, int cmd2, void *ptr) * when we re-enabled interrupts. When I muck with dcr, * is the irq_save/restore needed? */ - for (i = 0, cnum = 4;i < cmd2; i++, cnum++, cptr++) { - tmp.data = (pmds[smp_processor_id()][i] - + (ia64_get_pmd(cnum) & PERF_OVFL_VAL)); - tmp.counter_num = cnum; - if (copy_to_user(cptr, &tmp, sizeof(tmp))) - return -EFAULT; - //put_user(pmd, &cptr->data); + + + /* XXX: This needs to change to read more than just the counters */ + for (i = 0, cnum = PMU_FIRST_COUNTER;i < count; i++, cnum++, cptr++) { + + tmp.pmu_reg_data = (pmds[smp_processor_id()][i] + + (ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val)); + + tmp.pmu_reg_num = cnum; + + if (copy_to_user(cptr, &tmp, sizeof(tmp))) return -EFAULT; } +#if 0 +/* irrelevant with user monitors */ local_irq_save(flags); __asm__ __volatile__("ssm psr.pp"); dcr = ia64_get_dcr(); dcr |= IA64_DCR_PP; ia64_set_dcr(dcr); local_irq_restore(flags); +#endif break; case STOP_PMCS: ia64_set_pmc(0, 1); ia64_srlz_d(); - for (i = 0; i < MAX_PERF_COUNTER - used_by_system; ++i) + for (i = 0; i < MAX_PERF_COUNTER; ++i) ia64_set_pmc(4+i, 0); - if (!used_by_system) { - local_irq_save(flags); - dcr = ia64_get_dcr(); - dcr &= ~IA64_DCR_PP; - ia64_set_dcr(dcr); - local_irq_restore(flags); - } +#if 0 +/* irrelevant with user monitors */ + local_irq_save(flags); + dcr = ia64_get_dcr(); + dcr &= ~IA64_DCR_PP; + ia64_set_dcr(dcr); + local_irq_restore(flags); + ia64_psr(regs)->up = 0; +#endif + current->thread.flags &= ~(IA64_THREAD_PM_VALID); + break; default: @@ -187,13 +242,21 @@ update_counters (void) unsigned long mask, i, cnum, val; mask = ia64_get_pmc(0) >> 4; - for (i = 0, cnum = 4; i < MAX_PERF_COUNTER - used_by_system; cnum++, i++, mask >>= 1) { - val = 0; + for (i = 0, cnum = PMU_FIRST_COUNTER ; i < pmu_conf.max_counters; cnum++, i++, mask >>= 1) { + + + val = mask & 0x1 ? pmu_conf.perf_ovfl_val + 1 : 0; + if (mask & 0x1) - val += PERF_OVFL_VAL + 1; + printk(__FUNCTION__ " PMD%ld overflowed pmd=%lx pmod=%lx\n", cnum, ia64_get_pmd(cnum), pmds[smp_processor_id()][i]); + /* since we got an interrupt, might as well clear every pmd. */ - val += ia64_get_pmd(cnum) & PERF_OVFL_VAL; + val += ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val; + + printk(__FUNCTION__ " adding val=%lx to pmod[%ld]=%lx \n", val, i, pmds[smp_processor_id()][i]); + pmds[smp_processor_id()][i] += val; + ia64_set_pmd(cnum, 0); } } @@ -212,16 +275,69 @@ static struct irqaction perfmon_irqaction = { name: "perfmon" }; -void +static int +perfmon_proc_info(char *page) +{ + char *p = page; + u64 pmc0 = ia64_get_pmc(0); + + p += sprintf(p, "PMC[0]=%lx\n", pmc0); + + return p - page; +} + +static int +perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = perfmon_proc_info(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 struct proc_dir_entry *perfmon_dir; + +void __init perfmon_init (void) { + pal_perf_mon_info_u_t pm_info; + u64 pm_buffer[16]; + s64 status; + irq_desc[PERFMON_IRQ].status |= IRQ_PER_CPU; irq_desc[PERFMON_IRQ].handler = &irq_type_ia64_sapic; setup_irq(PERFMON_IRQ, &perfmon_irqaction); ia64_set_pmv(PERFMON_IRQ); ia64_srlz_d(); - printk("Initialized perfmon vector to %u\n",PERFMON_IRQ); + + printk("perfmon: Initialized vector to %u\n",PERFMON_IRQ); + + if ((status=ia64_pal_perf_mon_info(pm_buffer, &pm_info)) != 0) { + printk(__FUNCTION__ " pal call failed (%ld)\n", status); + return; + } + pmu_conf.perf_ovfl_val = perf_ovfl_val = (1L << pm_info.pal_perf_mon_info_s.width) - 1; + + /* XXX need to use PAL instead */ + pmu_conf.max_pmc = 13; + pmu_conf.max_pmd = 17; + pmu_conf.max_counters = pm_info.pal_perf_mon_info_s.generic; + + printk("perfmon: Counters are %d bits\n", pm_info.pal_perf_mon_info_s.width); + printk("perfmon: Maximum counter value 0x%lx\n", pmu_conf.perf_ovfl_val); + + /* + * for now here for debug purposes + */ + perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL); } void @@ -238,10 +354,13 @@ ia64_save_pm_regs (struct thread_struct *t) ia64_set_pmc(0, 1); ia64_srlz_d(); - for (i=0; i< IA64_NUM_PM_REGS - used_by_system ; i++) { - t->pmd[i] = ia64_get_pmd(4+i); + /* + * XXX: this will need to be extended beyong just counters + */ + for (i=0; i< IA64_NUM_PM_REGS; i++) { + t->pmd[i] = ia64_get_pmd(4+i); t->pmod[i] = pmds[smp_processor_id()][i]; - t->pmc[i] = ia64_get_pmc(4+i); + t->pmc[i] = ia64_get_pmc(4+i); } } @@ -250,7 +369,10 @@ ia64_load_pm_regs (struct thread_struct *t) { int i; - for (i=0; i< IA64_NUM_PM_REGS - used_by_system ; i++) { + /* + * XXX: this will need to be extended beyong just counters + */ + for (i=0; i< IA64_NUM_PM_REGS ; i++) { ia64_set_pmd(4+i, t->pmd[i]); pmds[smp_processor_id()][i] = t->pmod[i]; ia64_set_pmc(4+i, t->pmc[i]); @@ -262,7 +384,7 @@ ia64_load_pm_regs (struct thread_struct *t) #else /* !CONFIG_PERFMON */ asmlinkage unsigned long -sys_perfmonctl (int cmd1, int cmd2, void *ptr) +sys_perfmonctl (int cmd, int count, void *ptr) { return -ENOSYS; } diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index e586a4074..41db60a0c 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -294,7 +294,8 @@ copy_thread (int nr, unsigned long clone_flags, * call behavior where scratch registers are preserved across * system calls (unless used by the system call itself). */ -# define THREAD_FLAGS_TO_CLEAR (IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID) +# define THREAD_FLAGS_TO_CLEAR (IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID \ + | IA64_THREAD_PM_VALID) # define THREAD_FLAGS_TO_SET 0 p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR) | THREAD_FLAGS_TO_SET); @@ -333,6 +334,17 @@ do_copy_regs (struct unw_frame_info *info, void *arg) if (ia64_peek(pt, current, addr, &val) == 0) access_process_vm(current, addr, &val, sizeof(val), 1); + /* + * coredump format: + * r0-r31 + * NaT bits (for r0-r31; bit N == 1 iff rN is a NaT) + * predicate registers (p0-p63) + * b0-b7 + * ip cfm user-mask + * ar.rsc ar.bsp ar.bspstore ar.rnat + * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec + */ + /* r0 is zero */ for (i = 1, mask = (1UL << i); i < 32; ++i) { unw_get_gr(info, i, &dst[i], &nat); @@ -370,7 +382,6 @@ do_copy_regs (struct unw_frame_info *info, void *arg) void do_dump_fpu (struct unw_frame_info *info, void *arg) { - struct task_struct *fpu_owner = ia64_get_fpu_owner(); elf_fpreg_t *dst = arg; int i; @@ -384,10 +395,9 @@ do_dump_fpu (struct unw_frame_info *info, void *arg) for (i = 2; i < 32; ++i) unw_get_fr(info, i, dst + i); - if ((fpu_owner == current) || (current->thread.flags & IA64_THREAD_FPH_VALID)) { - ia64_sync_fph(current); + ia64_flush_fph(current); + if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) memcpy(dst + 32, current->thread.fph, 96*16); - } } #endif /* CONFIG_IA64_NEW_UNWIND */ @@ -463,7 +473,6 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst) unw_init_running(do_dump_fpu, dst); #else struct switch_stack *sw = ((struct switch_stack *) pt) - 1; - struct task_struct *fpu_owner = ia64_get_fpu_owner(); memset(dst, 0, sizeof (dst)); /* don't leak any "random" bits */ @@ -472,12 +481,9 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst) dst[8] = pt->f8; dst[9] = pt->f9; memcpy(dst + 10, &sw->f10, 22*16); /* f10-f31 are contiguous */ - if ((fpu_owner == current) || (current->thread.flags & IA64_THREAD_FPH_VALID)) { - if (fpu_owner == current) { - __ia64_save_fpu(current->thread.fph); - } + ia64_flush_fph(current); + if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) memcpy(dst + 32, current->thread.fph, 96*16); - } #endif return 1; /* f0-f31 are always valid so we always return 1 */ } @@ -501,14 +507,14 @@ pid_t kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) { struct task_struct *parent = current; - int result; + int result, tid; - clone(flags | CLONE_VM, 0); + tid = clone(flags | CLONE_VM, 0); if (parent != current) { result = (*fn)(arg); _exit(result); } - return 0; /* parent: just return */ + return tid; } /* @@ -520,9 +526,10 @@ flush_thread (void) /* drop floating-point and debug-register state if it exists: */ current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID); - if (ia64_get_fpu_owner() == current) { +#ifndef CONFIG_SMP + if (ia64_get_fpu_owner() == current) ia64_set_fpu_owner(0); - } +#endif } /* @@ -532,9 +539,28 @@ flush_thread (void) void exit_thread (void) { - if (ia64_get_fpu_owner() == current) { +#ifndef CONFIG_SMP + if (ia64_get_fpu_owner() == current) ia64_set_fpu_owner(0); +#endif +#ifdef CONFIG_PERFMON + /* stop monitoring */ + if ((current->thread.flags & IA64_THREAD_PM_VALID) != 0) { + /* + * we cannot rely on switch_to() to save the PMU + * context for the last time. There is a possible race + * condition in SMP mode between the child and the + * parent. by explicitly saving the PMU context here + * we garantee no race. this call we also stop + * monitoring + */ + ia64_save_pm_regs(¤t->thread); + /* + * make sure that switch_to() will not save context again + */ + current->thread.flags &= ~IA64_THREAD_PM_VALID; } +#endif } unsigned long diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 10868ce41..820a87854 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -376,7 +376,8 @@ ia64_peek (struct pt_regs *regs, struct task_struct *child, unsigned long addr, ret = 0; } else { if ((unsigned long) laddr >= (unsigned long) high_memory) { - printk("yikes: trying to access long at %p\n", laddr); + printk("yikes: trying to access long at %p\n", + (void *) laddr); return -EIO; } ret = *laddr; @@ -543,21 +544,48 @@ sync_thread_rbs (struct task_struct *child, struct mm_struct *mm, int make_writa } /* - * Ensure the state in child->thread.fph is up-to-date. + * Write f32-f127 back to task->thread.fph if it has been modified. */ -void -ia64_sync_fph (struct task_struct *child) +inline void +ia64_flush_fph (struct task_struct *task) { - 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; + struct ia64_psr *psr = ia64_psr(ia64_task_regs(task)); +#ifdef CONFIG_SMP + struct task_struct *fpu_owner = current; +#else + struct task_struct *fpu_owner = ia64_get_fpu_owner(); +#endif + + if (task == fpu_owner && psr->mfh) { + psr->mfh = 0; + ia64_save_fpu(&task->thread.fph[0]); + task->thread.flags |= IA64_THREAD_FPH_VALID; } - if (!(child->thread.flags & IA64_THREAD_FPH_VALID)) { - memset(&child->thread.fph, 0, sizeof(child->thread.fph)); - child->thread.flags |= IA64_THREAD_FPH_VALID; +} + +/* + * Sync the fph state of the task so that it can be manipulated + * through thread.fph. If necessary, f32-f127 are written back to + * thread.fph or, if the fph state hasn't been used before, thread.fph + * is cleared to zeroes. Also, access to f32-f127 is disabled to + * ensure that the task picks up the state from thread.fph when it + * executes again. + */ +void +ia64_sync_fph (struct task_struct *task) +{ + struct ia64_psr *psr = ia64_psr(ia64_task_regs(task)); + + ia64_flush_fph(task); + if (!(task->thread.flags & IA64_THREAD_FPH_VALID)) { + task->thread.flags |= IA64_THREAD_FPH_VALID; + memset(&task->thread.fph, 0, sizeof(task->thread.fph)); } +#ifndef CONFIG_SMP + if (ia64_get_fpu_owner() == task) + ia64_set_fpu_owner(0); +#endif + psr->dfh = 1; } #ifdef CONFIG_IA64_NEW_UNWIND @@ -589,6 +617,7 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data struct switch_stack *sw; struct unw_frame_info info; struct pt_regs *pt; + unsigned long pmd_tmp; pt = ia64_task_regs(child); sw = (struct switch_stack *) (child->thread.ksp + 16); @@ -600,7 +629,10 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data if (addr < PT_F127 + 16) { /* accessing fph */ - ia64_sync_fph(child); + if (write_access) + ia64_sync_fph(child); + else + ia64_flush_fph(child); ptr = (unsigned long *) ((unsigned long) &child->thread.fph + addr); } else if (addr >= PT_F10 && addr < PT_F15 + 16) { /* scratch registers untouched by kernel (saved in switch_stack) */ @@ -656,6 +688,9 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data case PT_B1: case PT_B2: case PT_B3: case PT_B4: case PT_B5: return unw_access_br(&info, (addr - PT_B1)/8 + 1, data, write_access); + case PT_AR_EC: + return unw_access_ar(&info, UNW_AR_EC, data, write_access); + case PT_AR_LC: return unw_access_ar(&info, UNW_AR_LC, data, write_access); @@ -759,7 +794,11 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data addr); return -1; } - } else { + } else +#ifdef CONFIG_PERFMON + if (addr < PT_PMD) +#endif + { /* access debug registers */ if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { @@ -782,6 +821,32 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data ptr += regnum; } +#ifdef CONFIG_PERFMON + else { + /* + * XXX: will eventually move back to perfmonctl() + */ + unsigned long pmd = (addr - PT_PMD) >> 3; + extern unsigned long perf_ovfl_val; + + /* we just use ptrace to read */ + if (write_access) return -1; + + if (pmd > 3) { + printk("ptrace: rejecting access to PMD[%ld] address 0x%lx\n", pmd, addr); + return -1; + } + + /* + * We always need to mask upper 32bits of pmd because value is random + */ + pmd_tmp = child->thread.pmod[pmd]+(child->thread.pmd[pmd]& perf_ovfl_val); + + /*printk(__FUNCTION__" child=%d reading pmd[%ld]=%lx\n", child->pid, pmd, pmd_tmp);*/ + + ptr = &pmd_tmp; + } +#endif if (write_access) *ptr = *data; else @@ -794,8 +859,9 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data static int access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access) { - unsigned long *ptr, *rbs, *bspstore, ndirty, regnum; + unsigned long *ptr = NULL, *rbs, *bspstore, ndirty, regnum; struct switch_stack *sw; + unsigned long pmd_tmp; struct pt_regs *pt; if ((addr & 0x7) != 0) @@ -803,7 +869,10 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data if (addr < PT_F127+16) { /* accessing fph */ - ia64_sync_fph(child); + if (write_access) + ia64_sync_fph(child); + else + ia64_flush_fph(child); ptr = (unsigned long *) ((unsigned long) &child->thread.fph + addr); } else if (addr < PT_F9+16) { /* accessing switch_stack or pt_regs: */ @@ -864,6 +933,14 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data *data = (pt->cr_ipsr & IPSR_READ_MASK); return 0; + case PT_AR_EC: + if (write_access) + sw->ar_pfs = (((*data & 0x3f) << 52) + | (sw->ar_pfs & ~(0x3fUL << 52))); + else + *data = (sw->ar_pfs >> 52) & 0x3f; + break; + case PT_R1: case PT_R2: case PT_R3: case PT_R4: case PT_R5: case PT_R6: case PT_R7: case PT_R8: case PT_R9: case PT_R10: case PT_R11: @@ -900,7 +977,12 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data /* disallow accessing anything else... */ return -1; } - } else { + } else +#ifdef CONFIG_PERFMON + if (addr < PT_PMD) +#endif + { + /* access debug registers */ if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { @@ -921,6 +1003,33 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data ptr += regnum; } +#ifdef CONFIG_PERFMON + else { + /* + * XXX: will eventually move back to perfmonctl() + */ + unsigned long pmd = (addr - PT_PMD) >> 3; + extern unsigned long perf_ovfl_val; + + /* we just use ptrace to read */ + if (write_access) return -1; + + if (pmd > 3) { + printk("ptrace: rejecting access to PMD[%ld] address 0x%lx\n", pmd, addr); + return -1; + } + + /* + * We always need to mask upper 32bits of pmd because value is random + */ + pmd_tmp = child->thread.pmod[pmd]+(child->thread.pmd[pmd]& perf_ovfl_val); + + /*printk(__FUNCTION__" child=%d reading pmd[%ld]=%lx\n", child->pid, pmd, pmd_tmp);*/ + + ptr = &pmd_tmp; + } +#endif + if (write_access) *ptr = *data; else @@ -996,10 +1105,12 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, ret = -ESRCH; if (!(child->ptrace & PT_PTRACED)) goto out_tsk; + if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) + if (request != PTRACE_KILL && request != PTRACE_PEEKUSR) goto out_tsk; } + if (child->p_pptr != current) goto out_tsk; diff --git a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c index f73cd8968..87c7befea 100644 --- a/arch/ia64/kernel/sal.c +++ b/arch/ia64/kernel/sal.c @@ -34,6 +34,7 @@ default_handler (void) } ia64_sal_handler ia64_sal = (ia64_sal_handler) default_handler; +ia64_sal_desc_ptc_t *ia64_ptc_domain_info; const char * ia64_sal_strerror (long status) @@ -127,6 +128,10 @@ ia64_sal_init (struct ia64_sal_systab *systab) ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp)); break; + case SAL_DESC_PTC: + ia64_ptc_domain_info = (ia64_sal_desc_ptc_t *)p; + break; + case SAL_DESC_AP_WAKEUP: #ifdef CONFIG_SMP { diff --git a/arch/ia64/kernel/semaphore.c b/arch/ia64/kernel/semaphore.c index 1bbe4feab..84ff34cf6 100644 --- a/arch/ia64/kernel/semaphore.c +++ b/arch/ia64/kernel/semaphore.c @@ -7,9 +7,9 @@ /* * Semaphores are implemented using a two-way counter: The "count" - * variable is decremented for each process that tries to aquire the + * variable is decremented for each process that tries to acquire the * semaphore, while the "sleepers" variable is a count of such - * aquires. + * acquires. * * Notably, the inline "up()" and "down()" functions can efficiently * test if they need to do any extra work (up needs to do something @@ -188,7 +188,7 @@ down_read_failed_biased (struct rw_semaphore *sem) } /* - * This gets called if we failed to aquire the lock and we are not + * This gets called if we failed to acquire the lock and we are not * biased to acquire the lock. We undo the decrement that was * done earlier, go to sleep, and then attempt to re-acquire the * lock afterwards. @@ -279,7 +279,7 @@ down_write_failed (struct rw_semaphore *sem) while (sem->count < 0) { set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); if (sem->count >= 0) - break; /* we must attempt to aquire or bias the lock */ + break; /* we must attempt to acquire or bias the lock */ schedule(); } diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 62e3e19ea..ed091d864 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -36,6 +36,7 @@ #include <asm/system.h> #include <asm/efi.h> #include <asm/mca.h> +#include <asm/smp.h> #ifdef CONFIG_BLK_DEV_RAM # include <linux/blk.h> @@ -43,7 +44,7 @@ extern char _end; -/* cpu_data[bootstrap_processor] is data for the bootstrap processor: */ +/* cpu_data[0] is data for the bootstrap processor: */ struct cpuinfo_ia64 cpu_data[NR_CPUS]; unsigned long ia64_cycles_per_usec; @@ -56,6 +57,8 @@ int cpu_now_booting = 0; volatile unsigned long cpu_online_map; #endif +unsigned long ia64_iobase; /* virtual address for I/O accesses */ + #define COMMAND_LINE_SIZE 512 char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */ @@ -111,6 +114,7 @@ free_available_memory (unsigned long start, unsigned long end, void *arg) void __init setup_arch (char **cmdline_p) { + extern unsigned long ia64_iobase; unsigned long max_pfn, bootmap_start, bootmap_size; unw_init(); @@ -157,7 +161,7 @@ setup_arch (char **cmdline_p) if (initrd_start >= PAGE_OFFSET) printk("Warning: boot loader passed virtual address " "for initrd, please upgrade the loader\n"); - } else + else #endif /* * The loader ONLY passes physical addresses @@ -215,9 +219,16 @@ setup_arch (char **cmdline_p) ia64_sal_init(efi.sal_systab); #ifdef CONFIG_SMP - bootstrap_processor = hard_smp_processor_id(); - current->processor = bootstrap_processor; + current->processor = 0; + cpu_physical_id(0) = hard_smp_processor_id(); #endif + /* + * Set `iobase' to the appropriate address in region 6 + * (uncached access range) + */ + __asm__ ("mov %0=ar.k0;;" : "=r"(ia64_iobase)); + ia64_iobase = __IA64_UNCACHED_OFFSET | (ia64_iobase & ~PAGE_OFFSET); + cpu_init(); /* initialize the bootstrap CPU */ #ifdef CONFIG_IA64_GENERIC @@ -259,6 +270,11 @@ setup_arch (char **cmdline_p) int get_cpuinfo (char *buffer) { +#ifdef CONFIG_SMP +# define lps c->loops_per_sec +#else +# define lps loops_per_sec +#endif char family[32], model[32], features[128], *cp, *p = buffer; struct cpuinfo_ia64 *c; unsigned long mask; @@ -309,7 +325,7 @@ get_cpuinfo (char *buffer) features, c->ppn, c->number, c->proc_freq / 1000000, c->proc_freq % 1000000, c->itc_freq / 1000000, c->itc_freq % 1000000, - loops_per_sec() / 500000, (loops_per_sec() / 5000) % 100); + lps / 500000, (lps / 5000) % 100); } return p - buffer; } @@ -371,8 +387,8 @@ identify_cpu (struct cpuinfo_ia64 *c) #endif phys_addr_size = vm1.pal_vm_info_1_s.phys_add_size; } - printk("processor implements %lu virtual and %lu physical address bits\n", - impl_va_msb + 1, phys_addr_size); + printk("CPU %d: %lu virtual and %lu physical address bits\n", + smp_processor_id(), impl_va_msb + 1, phys_addr_size); c->unimpl_va_mask = ~((7L<<61) | ((1L << (impl_va_msb + 1)) - 1)); c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1)); @@ -405,9 +421,12 @@ cpu_init (void) * do NOT defer TLB misses, page-not-present, access bit, or * debug faults but kernel code should not rely on any * particular setting of these bits. - */ ia64_set_dcr(IA64_DCR_DR | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_PP); + */ + ia64_set_dcr(IA64_DCR_DR | IA64_DCR_DK | IA64_DCR_DX ); +#ifndef CONFIG_SMP ia64_set_fpu_owner(0); /* initialize ar.k5 */ +#endif atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 12f312672..e0adf1981 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -147,11 +147,12 @@ restore_sigcontext (struct sigcontext *sc, struct sigscratch *scr) ia64_put_nat_bits(&scr->pt, &scr->sw, nat); /* restore the original scratch NaT bits */ #endif - if (flags & IA64_SC_FLAG_FPH_VALID) { - struct task_struct *fpu_owner = ia64_get_fpu_owner(); + if ((flags & IA64_SC_FLAG_FPH_VALID) != 0) { + struct ia64_psr *psr = ia64_psr(&scr->pt); __copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16); - if (fpu_owner == current) { + if (!psr->dfh) { + psr->mfh = 0; __ia64_load_fpu(current->thread.fph); } } @@ -235,9 +236,12 @@ ia64_rt_sigreturn (struct sigscratch *scr) goto give_sigsegv; sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); - current->blocked = set; - recalc_sigpending(current); + { + current->blocked = set; + recalc_sigpending(current); + } spin_unlock_irq(¤t->sigmask_lock); if (restore_sigcontext(sc, scr)) @@ -274,7 +278,6 @@ ia64_rt_sigreturn (struct sigscratch *scr) static long setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr) { - struct task_struct *fpu_owner = ia64_get_fpu_owner(); unsigned long flags = 0, ifs, nat; long err; @@ -286,11 +289,9 @@ setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr) /* if cr_ifs isn't valid, we got here through a syscall */ flags |= IA64_SC_FLAG_IN_SYSCALL; } - if ((fpu_owner == current) || (current->thread.flags & IA64_THREAD_FPH_VALID)) { + ia64_flush_fph(current); + if ((current->thread.flags & IA64_THREAD_FPH_VALID)) { flags |= IA64_SC_FLAG_FPH_VALID; - if (fpu_owner == current) { - __ia64_save_fpu(current->thread.fph); - } __copy_to_user(&sc->sc_fr[32], current->thread.fph, 96*16); } @@ -425,9 +426,11 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sigmask_lock); - sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); - sigaddset(¤t->blocked, sig); - recalc_sigpending(current); + { + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); + sigaddset(¤t->blocked, sig); + recalc_sigpending(current); + } spin_unlock_irq(¤t->sigmask_lock); } return 1; diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index d64305cf3..694711507 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -6,6 +6,8 @@ * * Lots of stuff stolen from arch/alpha/kernel/smp.c * + * 00/09/11 David Mosberger <davidm@hpl.hp.com> Do loops_per_sec calibration on each CPU. + * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> fixed logical processor id * 00/03/31 Rohit Seth <rohit.seth@intel.com> Fixes for Bootstrap Processor & cpu_online_map * now gets done here (instead of setup.c) * 99/10/05 davidm Update to bring it in sync with new command-line processing scheme. @@ -27,6 +29,7 @@ #include <asm/bitops.h> #include <asm/current.h> #include <asm/delay.h> +#include <asm/efi.h> #include <asm/io.h> #include <asm/irq.h> @@ -39,27 +42,31 @@ #include <asm/system.h> #include <asm/unistd.h> +extern void __init calibrate_delay(void); extern int cpu_idle(void * unused); -extern void _start(void); extern void machine_halt(void); +extern void start_ap(void); extern int cpu_now_booting; /* Used by head.S to find idle task */ extern volatile unsigned long cpu_online_map; /* Bitmap of available cpu's */ extern struct cpuinfo_ia64 cpu_data[NR_CPUS]; /* Duh... */ +struct smp_boot_data smp_boot_data __initdata; + spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; -struct smp_boot_data __initdata smp; -char __initdata no_int_routing = 0; +char __initdata no_int_routing; unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */ -volatile int __cpu_number_map[NR_CPUS] = { -1, }; /* SAPIC ID -> Logical ID */ -volatile int __cpu_logical_map[NR_CPUS] = { -1, }; /* logical ID -> SAPIC ID */ +volatile int __cpu_physical_id[NR_CPUS] = { -1, }; /* Logical ID -> SAPIC ID */ int smp_num_cpus = 1; -int bootstrap_processor = -1; /* SAPIC ID of BSP */ -int smp_threads_ready = 0; /* Set when the idlers are all forked */ -cycles_t cacheflush_time = 0; +volatile int smp_threads_ready; /* Set when the idlers are all forked */ +cycles_t cacheflush_time; unsigned long ap_wakeup_vector = -1; /* External Int to use to wakeup AP's */ + +static volatile unsigned long cpu_callin_map; +static volatile int smp_commenced; + static int max_cpus = -1; /* Command line */ static unsigned long ipi_op[NR_CPUS]; struct smp_call_struct { @@ -135,6 +142,7 @@ halt_processor(void) static inline int pointer_lock(void *lock, void *data, int retry) { + volatile long *ptr = lock; again: if (cmpxchg_acq((void **) lock, 0, data) == 0) return 0; @@ -142,7 +150,7 @@ pointer_lock(void *lock, void *data, int retry) if (!retry) return -EBUSY; - while (*(void **) lock) + while (*ptr) ; goto again; @@ -275,12 +283,10 @@ static inline void send_IPI_allbutself(int op) { int i; - int cpu_id = 0; for (i = 0; i < smp_num_cpus; i++) { - cpu_id = __cpu_logical_map[i]; - if (cpu_id != smp_processor_id()) - send_IPI_single(cpu_id, op); + if (i != smp_processor_id()) + send_IPI_single(i, op); } } @@ -290,7 +296,7 @@ send_IPI_all(int op) int i; for (i = 0; i < smp_num_cpus; i++) - send_IPI_single(__cpu_logical_map[i], op); + send_IPI_single(i, op); } static inline void @@ -335,7 +341,7 @@ int smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int retry, int wait) { struct smp_call_struct data; - long timeout; + unsigned long timeout; int cpus = 1; if (cpuid == smp_processor_id()) { @@ -387,7 +393,7 @@ int smp_call_function (void (*func) (void *info), void *info, int retry, int wait) { struct smp_call_struct data; - long timeout; + unsigned long timeout; int cpus = smp_num_cpus - 1; if (cpus == 0) @@ -453,80 +459,16 @@ smp_do_timer(struct pt_regs *regs) if (--data->prof_counter <= 0) { data->prof_counter = data->prof_multiplier; - /* - * update_process_times() expects us to have done irq_enter(). - * Besides, if we don't timer interrupts ignore the global - * interrupt lock, which is the WrongThing (tm) to do. - */ - irq_enter(cpu, 0); update_process_times(user); - irq_exit(cpu, 0); } } -static inline void __init -smp_calibrate_delay(int cpuid) -{ - struct cpuinfo_ia64 *c = &cpu_data[cpuid]; -#if 0 - unsigned long old = loops_per_sec; - extern void calibrate_delay(void); - - loops_per_sec = 0; - calibrate_delay(); - c->loops_per_sec = loops_per_sec; - loops_per_sec = old; -#else - c->loops_per_sec = loops_per_sec; -#endif -} - -/* - * SAL shoves the AP's here when we start them. Physical mode, no kernel TR, - * no RRs set, better than even chance that psr is bogus. Fix all that and - * call _start. In effect, pretend to be lilo. - * - * Stolen from lilo_start.c. Thanks David! - */ -void -start_ap(void) -{ - unsigned long flags; - - /* - * Install a translation register that identity maps the - * kernel's 256MB page(s). - */ - ia64_clear_ic(flags); - ia64_set_rr( 0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2)); - ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2)); - ia64_srlz_d(); - ia64_itr(0x3, 1, PAGE_OFFSET, - pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))), - _PAGE_SIZE_256M); - ia64_srlz_i(); - - flags = (IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH | - IA64_PSR_BN); - - asm volatile ("movl r8 = 1f\n" - ";;\n" - "mov cr.ipsr=%0\n" - "mov cr.iip=r8\n" - "mov cr.ifs=r0\n" - ";;\n" - "rfi;;" - "1:\n" - "movl r1 = __gp" :: "r"(flags) : "r8"); - _start(); -} - /* * AP's start using C here. */ void __init -smp_callin(void) +smp_callin (void) { extern void ia64_rid_init(void); extern void ia64_init_itm(void); @@ -534,12 +476,17 @@ smp_callin(void) #ifdef CONFIG_PERFMON extern void perfmon_init_percpu(void); #endif + int cpu = smp_processor_id(); - efi_map_pal_code(); + if (test_and_set_bit(cpu, &cpu_online_map)) { + printk("CPU#%d already initialized!\n", cpu); + machine_halt(); + } + efi_map_pal_code(); cpu_init(); - smp_setup_percpu_timer(smp_processor_id()); + smp_setup_percpu_timer(cpu); /* setup the CPU local timer tick */ ia64_init_itm(); @@ -552,16 +499,16 @@ smp_callin(void) ia64_set_lrr0(0, 1); ia64_set_lrr1(0, 1); - if (test_and_set_bit(smp_processor_id(), &cpu_online_map)) { - printk("CPU#%d already initialized!\n", smp_processor_id()); - machine_halt(); - } - while (!smp_threads_ready) - mb(); - local_irq_enable(); /* Interrupts have been off until now */ - smp_calibrate_delay(smp_processor_id()); - printk("SMP: CPU %d starting idle loop\n", smp_processor_id()); + + calibrate_delay(); + my_cpu_data.loops_per_sec = loops_per_sec; + + /* allow the master to continue */ + set_bit(cpu, &cpu_callin_map); + + /* finally, wait for the BP to finish initialization: */ + while (!smp_commenced); cpu_idle(NULL); } @@ -583,14 +530,13 @@ fork_by_hand(void) } /* - * Bring one cpu online. - * - * NB: cpuid is the CPU BUS-LOCAL ID, not the entire SAPIC ID. See asm/smp.h. + * Bring one cpu online. Return 0 if this fails for any reason. */ static int __init -smp_boot_one_cpu(int cpuid, int cpunum) +smp_boot_one_cpu(int cpu) { struct task_struct *idle; + int cpu_phys_id = cpu_physical_id(cpu); long timeout; /* @@ -603,50 +549,37 @@ smp_boot_one_cpu(int cpuid, int cpunum) * Sheesh . . . */ if (fork_by_hand() < 0) - panic("failed fork for CPU %d", cpuid); + panic("failed fork for CPU 0x%x", cpu_phys_id); /* * We remove it from the pidhash and the runqueue * once we got the process: */ idle = init_task.prev_task; if (!idle) - panic("No idle process for CPU %d", cpuid); - init_tasks[cpunum] = idle; + panic("No idle process for CPU 0x%x", cpu_phys_id); + init_tasks[cpu] = idle; del_from_runqueue(idle); unhash_process(idle); /* Schedule the first task manually. */ - idle->processor = cpuid; + idle->processor = cpu; idle->has_cpu = 1; /* Let _start know what logical CPU we're booting (offset into init_tasks[] */ - cpu_now_booting = cpunum; - + cpu_now_booting = cpu; + /* Kick the AP in the butt */ - ipi_send(cpuid, ap_wakeup_vector, IA64_IPI_DM_INT, 0); - ia64_srlz_i(); - mb(); + ipi_send(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); - /* - * OK, wait a bit for that CPU to finish staggering about. smp_callin() will - * call cpu_init() which will set a bit for this AP. When that bit flips, the AP - * is waiting for smp_threads_ready to be 1 and we can move on. - */ + /* wait up to 10s for the AP to start */ for (timeout = 0; timeout < 100000; timeout++) { - if (test_bit(cpuid, &cpu_online_map)) - goto alive; + if (test_bit(cpu, &cpu_callin_map)) + return 1; udelay(100); - barrier(); } - printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid); + printk(KERN_ERR "SMP: Processor 0x%x is stuck.\n", cpu_phys_id); return 0; - -alive: - /* Remember the AP data */ - __cpu_number_map[cpuid] = cpunum; - __cpu_logical_map[cpunum] = cpuid; - return 1; } @@ -663,21 +596,20 @@ smp_boot_cpus(void) unsigned long bogosum; /* Take care of some initial bookkeeping. */ - memset(&__cpu_number_map, -1, sizeof(__cpu_number_map)); - memset(&__cpu_logical_map, -1, sizeof(__cpu_logical_map)); + memset(&__cpu_physical_id, -1, sizeof(__cpu_physical_id)); memset(&ipi_op, 0, sizeof(ipi_op)); - /* Setup BSP mappings */ - __cpu_number_map[bootstrap_processor] = 0; - __cpu_logical_map[0] = bootstrap_processor; + /* Setup BP mappings */ + __cpu_physical_id[0] = hard_smp_processor_id(); - smp_calibrate_delay(smp_processor_id()); + /* on the BP, the kernel already called calibrate_delay_loop() in init/main.c */ + my_cpu_data.loops_per_sec = loops_per_sec; #if 0 smp_tune_scheduling(); #endif - smp_setup_percpu_timer(bootstrap_processor); + smp_setup_percpu_timer(0); - if (test_and_set_bit(bootstrap_processor, &cpu_online_map)) { + if (test_and_set_bit(0, &cpu_online_map)) { printk("CPU#%d already initialized!\n", smp_processor_id()); machine_halt(); } @@ -692,16 +624,18 @@ smp_boot_cpus(void) if (max_cpus != -1) printk("Limiting CPUs to %d\n", max_cpus); - if (smp.cpu_count > 1) { + if (smp_boot_data.cpu_count > 1) { printk(KERN_INFO "SMP: starting up secondaries.\n"); - for (i = 0; i < NR_CPUS; i++) { - if (smp.cpu_map[i] == -1 || - smp.cpu_map[i] == bootstrap_processor) + for (i = 0; i < smp_boot_data.cpu_count; i++) { + /* skip performance restricted and bootstrap cpu: */ + if (smp_boot_data.cpu_phys_id[i] == -1 + || smp_boot_data.cpu_phys_id[i] == hard_smp_processor_id()) continue; - if (smp_boot_one_cpu(smp.cpu_map[i], cpu_count) == 0) - continue; + cpu_physical_id(cpu_count) = smp_boot_data.cpu_phys_id[i]; + if (!smp_boot_one_cpu(cpu_count)) + continue; /* failed */ cpu_count++; /* Count good CPUs only... */ /* @@ -731,20 +665,12 @@ smp_boot_cpus(void) } /* - * Called from main.c by each AP. + * Called when the BP is just about to fire off init. */ void __init smp_commence(void) { - mb(); -} - -/* - * Not used; part of the i386 bringup - */ -void __init -initialize_secondary(void) -{ + smp_commenced = 1; } int __init @@ -759,9 +685,7 @@ setup_profiling_timer(unsigned int multiplier) * * Setup of the IPI irq handler is done in irq.c:init_IRQ_SMP(). * - * So this just gets the BSP SAPIC ID and print's it out. Dull, huh? - * - * Not anymore. This also registers the AP OS_MC_REDVEZ address with SAL. + * This also registers the AP OS_MC_REDVEZ address with SAL. */ void __init init_smp_config(void) @@ -772,9 +696,6 @@ init_smp_config(void) } *ap_startup; long sal_ret; - /* Grab the BSP ID */ - bootstrap_processor = hard_smp_processor_id(); - /* Tell SAL where to drop the AP's. */ ap_startup = (struct fptr *) start_ap; sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 3550cc390..83bff8b0c 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -1,2 +1,74 @@ -unsigned long cpu_online_map; +/* + * SMP Support + * + * Application processor startup code, moved from smp.c to better support kernel profile + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/smp.h> +#include <linux/kernel_stat.h> +#include <linux/mm.h> +#include <linux/delay.h> + +#include <asm/atomic.h> +#include <asm/bitops.h> +#include <asm/current.h> +#include <asm/delay.h> +#include <asm/efi.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/pgalloc.h> +#include <asm/processor.h> +#include <asm/ptrace.h> +#include <asm/sal.h> +#include <asm/system.h> +#include <asm/unistd.h> + +/* + * SAL shoves the AP's here when we start them. Physical mode, no kernel TR, + * no RRs set, better than even chance that psr is bogus. Fix all that and + * call _start. In effect, pretend to be lilo. + * + * Stolen from lilo_start.c. Thanks David! + */ +void +start_ap(void) +{ + extern void _start (void); + unsigned long flags; + + /* + * Install a translation register that identity maps the + * kernel's 256MB page(s). + */ + ia64_clear_ic(flags); + ia64_set_rr( 0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2)); + ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2)); + ia64_srlz_d(); + ia64_itr(0x3, 1, PAGE_OFFSET, + pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))), + _PAGE_SIZE_256M); + ia64_srlz_i(); + + flags = (IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH | + IA64_PSR_BN); + + asm volatile ("movl r8 = 1f\n" + ";;\n" + "mov cr.ipsr=%0\n" + "mov cr.iip=r8\n" + "mov cr.ifs=r0\n" + ";;\n" + "rfi;;" + "1:\n" + "movl r1 = __gp" :: "r"(flags) : "r8"); + _start(); +} + diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c index a3e5242fc..f78512229 100644 --- a/arch/ia64/kernel/sys_ia64.c +++ b/arch/ia64/kernel/sys_ia64.c @@ -147,7 +147,7 @@ sys_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, l struct pt_regs *regs = (struct pt_regs *) &stack; addr = do_mmap2(addr, len, prot, flags, fd, pgoff); - if (!IS_ERR(addr)) + if (!IS_ERR((void *) addr)) regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */ return addr; } @@ -162,26 +162,12 @@ sys_mmap (unsigned long addr, unsigned long len, int prot, int flags, return -EINVAL; addr = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); - if (!IS_ERR(addr)) + if (!IS_ERR((void *) addr)) regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */ return addr; } asmlinkage long -sys_ioperm (unsigned long from, unsigned long num, int on) -{ - printk(KERN_ERR "sys_ioperm(from=%lx, num=%lx, on=%d)\n", from, num, on); - return -EIO; -} - -asmlinkage long -sys_iopl (int level, long arg1, long arg2, long arg3) -{ - printk(KERN_ERR "sys_iopl(level=%d)!\n", level); - return -ENOSYS; -} - -asmlinkage long sys_vm86 (long arg0, long arg1, long arg2, long arg3) { printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); @@ -204,7 +190,7 @@ ia64_create_module (const char *name_user, size_t size, long arg2, long arg3, unsigned long addr; addr = sys_create_module (name_user, size); - if (!IS_ERR(addr)) + if (!IS_ERR((void *) addr)) regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */ return addr; } diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 96ff76c01..5e54e4f4b 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -183,7 +183,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) #ifdef CONFIG_SMP smp_do_timer(regs); - if (smp_processor_id() == bootstrap_processor) + if (smp_processor_id() == 0) do_timer(regs); #else do_timer(regs); @@ -303,7 +303,7 @@ ia64_init_itm (void) itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; itm.delta = itc_freq / HZ; - printk("timer: CPU %d base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n", + printk("CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n", smp_processor_id(), platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000); diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index bf1abd839..43340bf85 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -192,38 +192,45 @@ ia64_ni_syscall (unsigned long arg0, unsigned long arg1, unsigned long arg2, uns } /* - * disabled_fp_fault() is called when a user-level process attempts to - * access one of the registers f32..f127 while it doesn't own the + * disabled_fph_fault() is called when a user-level process attempts + * to access one of the registers f32..f127 when it doesn't own the * fp-high register partition. When this happens, we save the current * fph partition in the task_struct of the fpu-owner (if necessary) * and then load the fp-high partition of the current task (if - * necessary). + * necessary). Note that the kernel has access to fph by the time we + * get here, as the IVT's "Diabled FP-Register" handler takes care of + * clearing psr.dfh. */ static inline void disabled_fph_fault (struct pt_regs *regs) { - struct task_struct *fpu_owner = ia64_get_fpu_owner(); + struct ia64_psr *psr = ia64_psr(regs); - /* 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); + /* first, grant user-level access to fph partition: */ + psr->dfh = 0; +#ifndef CONFIG_SMP + { + struct task_struct *fpu_owner = ia64_get_fpu_owner(); - 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); - } - if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) { - __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; - } + if (fpu_owner == current) + return; + + if (fpu_owner) + ia64_flush_fph(fpu_owner); + + ia64_set_fpu_owner(current); + } +#endif /* !CONFIG_SMP */ + if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) { + __ia64_load_fpu(current->thread.fph); + psr->mfh = 0; + } else { + __ia64_init_fpu(); + /* + * Set mfh because the state in thread.fph does not match the state in + * the fph partition. + */ + psr->mfh = 1; } } @@ -247,20 +254,21 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long * kernel, so set those bits in the mask and set the low volatile * pointer to point to these registers. */ - fp_state.bitmask_low64 = 0xffc0; /* bit6..bit15 */ #ifndef FPSWA_BUG - fp_state.fp_state_low_volatile = ®s->f6; + fp_state.bitmask_low64 = 0x3c0; /* bit 6..9 */ + fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) ®s->f6; #else + fp_state.bitmask_low64 = 0xffc0; /* bit6..bit15 */ f6_15[0] = regs->f6; f6_15[1] = regs->f7; f6_15[2] = regs->f8; f6_15[3] = regs->f9; - __asm__ ("stf.spill %0=f10" : "=m"(f6_15[4])); - __asm__ ("stf.spill %0=f11" : "=m"(f6_15[5])); - __asm__ ("stf.spill %0=f12" : "=m"(f6_15[6])); - __asm__ ("stf.spill %0=f13" : "=m"(f6_15[7])); - __asm__ ("stf.spill %0=f14" : "=m"(f6_15[8])); - __asm__ ("stf.spill %0=f15" : "=m"(f6_15[9])); + __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_15[4])); + __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_15[5])); + __asm__ ("stf.spill %0=f12%P0" : "=m"(f6_15[6])); + __asm__ ("stf.spill %0=f13%P0" : "=m"(f6_15[7])); + __asm__ ("stf.spill %0=f14%P0" : "=m"(f6_15[8])); + __asm__ ("stf.spill %0=f15%P0" : "=m"(f6_15[9])); fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_15; #endif /* @@ -279,12 +287,12 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long (unsigned long *) isr, (unsigned long *) pr, (unsigned long *) ifs, &fp_state); #ifdef FPSWA_BUG - __asm__ ("ldf.fill f10=%0" :: "m"(f6_15[4])); - __asm__ ("ldf.fill f11=%0" :: "m"(f6_15[5])); - __asm__ ("ldf.fill f12=%0" :: "m"(f6_15[6])); - __asm__ ("ldf.fill f13=%0" :: "m"(f6_15[7])); - __asm__ ("ldf.fill f14=%0" :: "m"(f6_15[8])); - __asm__ ("ldf.fill f15=%0" :: "m"(f6_15[9])); + __asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_15[4])); + __asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_15[5])); + __asm__ ("ldf.fill f12=%0%P0" :: "m"(f6_15[6])); + __asm__ ("ldf.fill f13=%0%P0" :: "m"(f6_15[7])); + __asm__ ("ldf.fill f14=%0%P0" :: "m"(f6_15[8])); + __asm__ ("ldf.fill f15=%0%P0" :: "m"(f6_15[9])); regs->f6 = f6_15[0]; regs->f7 = f6_15[1]; regs->f8 = f6_15[2]; diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c index 7ca1146a0..7cc238a83 100644 --- a/arch/ia64/kernel/unaligned.c +++ b/arch/ia64/kernel/unaligned.c @@ -278,9 +278,9 @@ set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) bspstore = (unsigned long *)regs->ar_bspstore; DPRINT(("rse_slot_num=0x%lx\n",ia64_rse_slot_num((unsigned long *)sw->ar_bspstore))); - DPRINT(("kbs=%p nlocals=%ld\n", kbs, nlocals)); + DPRINT(("kbs=%p nlocals=%ld\n", (void *) kbs, nlocals)); DPRINT(("bspstore next rnat slot %p\n", - ia64_rse_rnat_addr((unsigned long *)sw->ar_bspstore))); + (void *) ia64_rse_rnat_addr((unsigned long *)sw->ar_bspstore))); DPRINT(("on_kbs=%ld rnats=%ld\n", on_kbs, ((sw->ar_bspstore-(unsigned long)kbs)>>3) - on_kbs)); @@ -292,7 +292,7 @@ set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) addr = slot = ia64_rse_skip_regs(bsp, r1 - 32); DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n", - ubs_end, bsp, addr, ia64_rse_slot_num(addr))); + (void *) ubs_end, (void *) bsp, (void *) addr, ia64_rse_slot_num(addr))); ia64_poke(regs, current, (unsigned long)addr, val); @@ -303,7 +303,7 @@ set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) ia64_peek(regs, current, (unsigned long)addr, &rnats); DPRINT(("rnat @%p = 0x%lx nat=%d rnatval=%lx\n", - addr, rnats, nat, rnats &ia64_rse_slot_num(slot))); + (void *) addr, rnats, nat, rnats &ia64_rse_slot_num(slot))); if (nat) { rnats |= __IA64_UL(1) << ia64_rse_slot_num(slot); @@ -312,7 +312,7 @@ set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) } ia64_poke(regs, current, (unsigned long)addr, rnats); - DPRINT(("rnat changed to @%p = 0x%lx\n", addr, rnats)); + DPRINT(("rnat changed to @%p = 0x%lx\n", (void *) addr, rnats)); } @@ -373,7 +373,7 @@ get_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat addr = slot = ia64_rse_skip_regs(bsp, r1 - 32); DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n", - ubs_end, bsp, addr, ia64_rse_slot_num(addr))); + (void *) ubs_end, (void *) bsp, (void *) addr, ia64_rse_slot_num(addr))); ia64_peek(regs, current, (unsigned long)addr, val); @@ -383,7 +383,7 @@ get_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat addr = ia64_rse_rnat_addr(addr); ia64_peek(regs, current, (unsigned long)addr, &rnats); - DPRINT(("rnat @%p = 0x%lx\n", addr, rnats)); + DPRINT(("rnat @%p = 0x%lx\n", (void *) addr, rnats)); if (nat) *nat = rnats >> ia64_rse_slot_num(slot) & 0x1; @@ -437,13 +437,13 @@ setreg(unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs) * UNAT bit_pos = GR[r3]{8:3} form EAS-2.4 */ bitmask = __IA64_UL(1) << (addr >> 3 & 0x3f); - DPRINT(("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, unat, *unat)); + DPRINT(("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, (void *) unat, *unat)); if (nat) { *unat |= bitmask; } else { *unat &= ~bitmask; } - DPRINT(("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, unat,*unat)); + DPRINT(("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat)); } #define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR) @@ -455,16 +455,15 @@ setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) unsigned long addr; /* - * From EAS-2.5: FPDisableFault has higher priority than - * Unaligned Fault. Thus, when we get here, we know the partition is - * enabled. + * From EAS-2.5: FPDisableFault has higher priority than Unaligned + * Fault. Thus, when we get here, we know the partition is enabled. + * To update f32-f127, there are three choices: + * + * (1) save f32-f127 to thread.fph and update the values there + * (2) use a gigantic switch statement to directly access the registers + * (3) generate code on the fly to update the desired register * - * The registers [32-127] are ususally saved in the tss. When get here, - * they are NECESSARILY live because they are only saved explicitely. - * We have 3 ways of updating the values: force a save of the range - * in tss, use a gigantic switch/case statement or generate code on the - * fly to store to the right register. - * For now, we are using the (slow) save/restore way. + * For now, we are using approach (1). */ if (regnum >= IA64_FIRST_ROTATING_FR) { ia64_sync_fph(current); @@ -491,7 +490,6 @@ setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) * let's do it for safety. */ regs->cr_ipsr |= IA64_PSR_MFL; - } } @@ -522,12 +520,12 @@ getfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) * Unaligned Fault. Thus, when we get here, we know the partition is * enabled. * - * When regnum > 31, the register is still live and - * we need to force a save to the tss to get access to it. - * See discussion in setfpreg() for reasons and other ways of doing this. + * When regnum > 31, the register is still live and we need to force a save + * to current->thread.fph to get access to it. See discussion in setfpreg() + * for reasons and other ways of doing this. */ if (regnum >= IA64_FIRST_ROTATING_FR) { - ia64_sync_fph(current); + ia64_flush_fph(current); *fpval = current->thread.fph[IA64_FPH_OFFS(regnum)]; } else { /* @@ -1084,9 +1082,9 @@ emulate_load_floatpair(unsigned long ifa, load_store_t *ld, struct pt_regs *regs /* * XXX fixme * - * A possible optimization would be to drop fpr_final - * and directly use the storage from the saved context i.e., - * the actual final destination (pt_regs, switch_stack or tss). + * A possible optimization would be to drop fpr_final and directly + * use the storage from the saved context i.e., the actual final + * destination (pt_regs, switch_stack or thread structure). */ setfpreg(ld->r1, &fpr_final[0], regs); setfpreg(ld->imm, &fpr_final[1], regs); @@ -1212,9 +1210,9 @@ emulate_load_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) /* * XXX fixme * - * A possible optimization would be to drop fpr_final - * and directly use the storage from the saved context i.e., - * the actual final destination (pt_regs, switch_stack or tss). + * A possible optimization would be to drop fpr_final and directly + * use the storage from the saved context i.e., the actual final + * destination (pt_regs, switch_stack or thread structure). */ setfpreg(ld->r1, &fpr_final, regs); } @@ -1223,9 +1221,7 @@ emulate_load_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) * check for updates on any loads */ if (ld->op == 0x7 || ld->m) - emulate_load_updates(ld->op == 0x7 ? UPD_IMMEDIATE: UPD_REG, - ld, regs, ifa); - + emulate_load_updates(ld->op == 0x7 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa); /* * invalidate ALAT entry in case of advanced floating point loads diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index 5d0049f32..21a2ead16 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c @@ -66,7 +66,7 @@ #define UNW_STATS 0 /* WARNING: this disabled interrupts for long time-spans!! */ #if UNW_DEBUG - static long unw_debug_level = 1; + static long unw_debug_level = 255; # define debug(level,format...) if (unw_debug_level > level) printk(format) # define dprintk(format...) printk(format) # define inline @@ -111,7 +111,7 @@ static struct { struct unw_table kernel_table; /* hash table that maps instruction pointer to script index: */ - unw_hash_index_t hash[UNW_HASH_SIZE]; + unsigned short hash[UNW_HASH_SIZE]; /* script cache: */ struct unw_script cache[UNW_CACHE_SIZE]; @@ -152,47 +152,47 @@ static struct { UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR }, preg_index: { - struct_offset(struct unw_frame_info, pri_unat)/8, /* PRI_UNAT_GR */ - struct_offset(struct unw_frame_info, pri_unat)/8, /* PRI_UNAT_MEM */ - struct_offset(struct unw_frame_info, pbsp)/8, - struct_offset(struct unw_frame_info, bspstore)/8, - struct_offset(struct unw_frame_info, pfs)/8, - struct_offset(struct unw_frame_info, rnat)/8, + struct_offset(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_GR */ + struct_offset(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_MEM */ + struct_offset(struct unw_frame_info, bsp_loc)/8, + struct_offset(struct unw_frame_info, bspstore_loc)/8, + struct_offset(struct unw_frame_info, pfs_loc)/8, + struct_offset(struct unw_frame_info, rnat_loc)/8, struct_offset(struct unw_frame_info, psp)/8, - struct_offset(struct unw_frame_info, rp)/8, + struct_offset(struct unw_frame_info, rp_loc)/8, struct_offset(struct unw_frame_info, r4)/8, struct_offset(struct unw_frame_info, r5)/8, struct_offset(struct unw_frame_info, r6)/8, struct_offset(struct unw_frame_info, r7)/8, - struct_offset(struct unw_frame_info, unat)/8, - struct_offset(struct unw_frame_info, pr)/8, - struct_offset(struct unw_frame_info, lc)/8, - struct_offset(struct unw_frame_info, fpsr)/8, - struct_offset(struct unw_frame_info, b1)/8, - struct_offset(struct unw_frame_info, b2)/8, - struct_offset(struct unw_frame_info, b3)/8, - struct_offset(struct unw_frame_info, b4)/8, - struct_offset(struct unw_frame_info, b5)/8, - struct_offset(struct unw_frame_info, f2)/8, - struct_offset(struct unw_frame_info, f3)/8, - struct_offset(struct unw_frame_info, f4)/8, - struct_offset(struct unw_frame_info, f5)/8, - struct_offset(struct unw_frame_info, fr[16 - 16])/8, - struct_offset(struct unw_frame_info, fr[17 - 16])/8, - struct_offset(struct unw_frame_info, fr[18 - 16])/8, - struct_offset(struct unw_frame_info, fr[19 - 16])/8, - struct_offset(struct unw_frame_info, fr[20 - 16])/8, - struct_offset(struct unw_frame_info, fr[21 - 16])/8, - struct_offset(struct unw_frame_info, fr[22 - 16])/8, - struct_offset(struct unw_frame_info, fr[23 - 16])/8, - struct_offset(struct unw_frame_info, fr[24 - 16])/8, - struct_offset(struct unw_frame_info, fr[25 - 16])/8, - struct_offset(struct unw_frame_info, fr[26 - 16])/8, - struct_offset(struct unw_frame_info, fr[27 - 16])/8, - struct_offset(struct unw_frame_info, fr[28 - 16])/8, - struct_offset(struct unw_frame_info, fr[29 - 16])/8, - struct_offset(struct unw_frame_info, fr[30 - 16])/8, - struct_offset(struct unw_frame_info, fr[31 - 16])/8, + struct_offset(struct unw_frame_info, unat_loc)/8, + struct_offset(struct unw_frame_info, pr_loc)/8, + struct_offset(struct unw_frame_info, lc_loc)/8, + struct_offset(struct unw_frame_info, fpsr_loc)/8, + struct_offset(struct unw_frame_info, b1_loc)/8, + struct_offset(struct unw_frame_info, b2_loc)/8, + struct_offset(struct unw_frame_info, b3_loc)/8, + struct_offset(struct unw_frame_info, b4_loc)/8, + struct_offset(struct unw_frame_info, b5_loc)/8, + struct_offset(struct unw_frame_info, f2_loc)/8, + struct_offset(struct unw_frame_info, f3_loc)/8, + struct_offset(struct unw_frame_info, f4_loc)/8, + struct_offset(struct unw_frame_info, f5_loc)/8, + struct_offset(struct unw_frame_info, fr_loc[16 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[17 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[18 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[19 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[20 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[21 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[22 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[23 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[24 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[25 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[26 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[27 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[28 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[29 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[30 - 16])/8, + struct_offset(struct unw_frame_info, fr_loc[31 - 16])/8, }, hash : { [0 ... UNW_HASH_SIZE - 1] = -1 }, #if UNW_DEBUG @@ -211,6 +211,27 @@ static struct { /* Unwind accessors. */ +/* + * Returns offset of rREG in struct pt_regs. + */ +static inline unsigned long +pt_regs_off (unsigned long reg) +{ + unsigned long off =0; + + if (reg >= 1 && reg <= 3) + off = struct_offset(struct pt_regs, r1) + 8*(reg - 1); + else if (reg <= 11) + off = struct_offset(struct pt_regs, r8) + 8*(reg - 8); + else if (reg <= 15) + off = struct_offset(struct pt_regs, r12) + 8*(reg - 12); + else if (reg <= 31) + off = struct_offset(struct pt_regs, r16) + 8*(reg - 16); + else + dprintk("unwind: bad scratch reg r%lu\n", reg); + return off; +} + int unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char *nat, int write) { @@ -251,26 +272,23 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char } /* fall through */ case UNW_NAT_NONE: + dummy_nat = 0; nat_addr = &dummy_nat; break; - case UNW_NAT_SCRATCH: - if (info->pri_unat) - nat_addr = info->pri_unat; - else - nat_addr = &info->sw->caller_unat; - case UNW_NAT_PRI_UNAT: + case UNW_NAT_MEMSTK: nat_mask = (1UL << ((long) addr & 0x1f8)/8); break; - case UNW_NAT_STACKED: + case UNW_NAT_REGSTK: nat_addr = ia64_rse_rnat_addr(addr); if ((unsigned long) addr < info->regstk.limit || (unsigned long) addr >= info->regstk.top) { - dprintk("unwind: 0x%p outside of regstk " - "[0x%lx-0x%lx)\n", addr, - info->regstk.limit, info->regstk.top); + dprintk("unwind: %p outside of regstk " + "[0x%lx-0x%lx)\n", (void *) addr, + info->regstk.limit, + info->regstk.top); return -1; } if ((unsigned long) nat_addr >= info->regstk.top) @@ -289,18 +307,11 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char pt = (struct pt_regs *) info->psp - 1; else pt = (struct pt_regs *) info->sp - 1; - if (regnum <= 3) - addr = &pt->r1 + (regnum - 1); - else if (regnum <= 11) - addr = &pt->r8 + (regnum - 8); - else if (regnum <= 15) - addr = &pt->r12 + (regnum - 12); - else - addr = &pt->r16 + (regnum - 16); - if (info->pri_unat) - nat_addr = info->pri_unat; + addr = (unsigned long *) ((long) pt + pt_regs_off(regnum)); + if (info->pri_unat_loc) + nat_addr = info->pri_unat_loc; else - nat_addr = &info->sw->caller_unat; + nat_addr = &info->sw->ar_unat; nat_mask = (1UL << ((long) addr & 0x1f8)/8); } } else { @@ -320,7 +331,10 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char if (write) { *addr = *val; - *nat_addr = (*nat_addr & ~nat_mask) | nat_mask; + if (*nat) + *nat_addr |= nat_mask; + else + *nat_addr &= ~nat_mask; } else { *val = *addr; *nat = (*nat_addr & nat_mask) != 0; @@ -346,7 +360,7 @@ unw_access_br (struct unw_frame_info *info, int regnum, unsigned long *val, int /* preserved: */ case 1: case 2: case 3: case 4: case 5: - addr = *(&info->b1 + (regnum - 1)); + addr = *(&info->b1_loc + (regnum - 1)); if (!addr) addr = &info->sw->b1 + (regnum - 1); break; @@ -379,7 +393,7 @@ unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, pt = (struct pt_regs *) info->sp - 1; if (regnum <= 5) { - addr = *(&info->f2 + (regnum - 2)); + addr = *(&info->f2_loc + (regnum - 2)); if (!addr) addr = &info->sw->f2 + (regnum - 2); } else if (regnum <= 15) { @@ -388,13 +402,16 @@ unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, else addr = &info->sw->f10 + (regnum - 10); } else if (regnum <= 31) { - addr = info->fr[regnum - 16]; + addr = info->fr_loc[regnum - 16]; if (!addr) addr = &info->sw->f16 + (regnum - 16); } else { struct task_struct *t = info->task; - ia64_sync_fph(t); + if (write) + ia64_sync_fph(t); + else + ia64_flush_fph(t); addr = t->thread.fph + (regnum - 32); } @@ -418,52 +435,53 @@ unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int switch (regnum) { case UNW_AR_BSP: - addr = info->pbsp; + addr = info->bsp_loc; if (!addr) addr = &info->sw->ar_bspstore; break; case UNW_AR_BSPSTORE: - addr = info->bspstore; + addr = info->bspstore_loc; if (!addr) addr = &info->sw->ar_bspstore; break; case UNW_AR_PFS: - addr = info->pfs; + addr = info->pfs_loc; if (!addr) addr = &info->sw->ar_pfs; break; case UNW_AR_RNAT: - addr = info->rnat; + addr = info->rnat_loc; if (!addr) addr = &info->sw->ar_rnat; break; case UNW_AR_UNAT: - addr = info->unat; + addr = info->unat_loc; if (!addr) addr = &info->sw->ar_unat; break; case UNW_AR_LC: - addr = info->lc; + addr = info->lc_loc; if (!addr) addr = &info->sw->ar_lc; break; case UNW_AR_EC: - if (!info->cfm) + if (!info->cfm_loc) return -1; if (write) - *info->cfm = (*info->cfm & ~(0x3fUL << 52)) | ((*val & 0x3f) << 52); + *info->cfm_loc = + (*info->cfm_loc & ~(0x3fUL << 52)) | ((*val & 0x3f) << 52); else - *val = (*info->cfm >> 52) & 0x3f; + *val = (*info->cfm_loc >> 52) & 0x3f; return 0; case UNW_AR_FPSR: - addr = info->fpsr; + addr = info->fpsr_loc; if (!addr) addr = &info->sw->ar_fpsr; break; @@ -493,7 +511,7 @@ unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write) { unsigned long *addr; - addr = info->pr; + addr = info->pr_loc; if (!addr) addr = &info->sw->pr; @@ -605,9 +623,8 @@ finish_prologue (struct unw_state_record *sr) int i; /* - * First, resolve implicit register save locations - * (see Section "11.4.2.3 Rules for Using Unwind - * Descriptors", rule 3): + * First, resolve implicit register save locations (see Section "11.4.2.3 Rules + * for Using Unwind Descriptors", rule 3): */ for (i = 0; i < (int) sizeof(unw.save_order)/sizeof(unw.save_order[0]); ++i) { reg = sr->curr.reg + unw.save_order[i]; @@ -1045,16 +1062,16 @@ desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word static inline unw_hash_index_t hash (unsigned long ip) { -# define magic 0x9e3779b97f4a7c16 /* (sqrt(5)/2-1)*2^64 */ +# define magic 0x9e3779b97f4a7c16 /* based on (sqrt(5)/2-1)*2^64 */ return (ip >> 4)*magic >> (64 - UNW_LOG_HASH_SIZE); } static inline long -cache_match (struct unw_script *script, unsigned long ip, unsigned long pr_val) +cache_match (struct unw_script *script, unsigned long ip, unsigned long pr) { read_lock(&script->lock); - if ((ip) == (script)->ip && (((pr_val) ^ (script)->pr_val) & (script)->pr_mask) == 0) + if (ip == script->ip && ((pr ^ script->pr_val) & script->pr_mask) == 0) /* keep the read lock... */ return 1; read_unlock(&script->lock); @@ -1065,21 +1082,26 @@ static inline struct unw_script * script_lookup (struct unw_frame_info *info) { struct unw_script *script = unw.cache + info->hint; - unsigned long ip, pr_val; + unsigned short index; + unsigned long ip, pr; STAT(++unw.stat.cache.lookups); ip = info->ip; - pr_val = info->pr_val; + pr = info->pr; - if (cache_match(script, ip, pr_val)) { + if (cache_match(script, ip, pr)) { STAT(++unw.stat.cache.hinted_hits); return script; } - script = unw.cache + unw.hash[hash(ip)]; + index = unw.hash[hash(ip)]; + if (index >= UNW_CACHE_SIZE) + return 0; + + script = unw.cache + index; while (1) { - if (cache_match(script, ip, pr_val)) { + if (cache_match(script, ip, pr)) { /* update hint; no locking required as single-word writes are atomic */ STAT(++unw.stat.cache.normal_hits); unw.cache[info->prev_script].hint = script - unw.cache; @@ -1099,8 +1121,8 @@ static inline struct unw_script * script_new (unsigned long ip) { struct unw_script *script, *prev, *tmp; + unw_hash_index_t index; unsigned long flags; - unsigned char index; unsigned short head; STAT(++unw.stat.script.news); @@ -1133,22 +1155,24 @@ script_new (unsigned long ip) unw.lru_tail = head; /* remove the old script from the hash table (if it's there): */ - index = hash(script->ip); - tmp = unw.cache + unw.hash[index]; - prev = 0; - while (1) { - if (tmp == script) { - if (prev) - prev->coll_chain = tmp->coll_chain; - else - unw.hash[index] = tmp->coll_chain; - break; - } else - prev = tmp; - if (tmp->coll_chain >= UNW_CACHE_SIZE) + if (script->ip) { + index = hash(script->ip); + tmp = unw.cache + unw.hash[index]; + prev = 0; + while (1) { + if (tmp == script) { + if (prev) + prev->coll_chain = tmp->coll_chain; + else + unw.hash[index] = tmp->coll_chain; + break; + } else + prev = tmp; + if (tmp->coll_chain >= UNW_CACHE_SIZE) /* old script wasn't in the hash-table */ - break; - tmp = unw.cache + tmp->coll_chain; + break; + tmp = unw.cache + tmp->coll_chain; + } } /* enter new script in the hash table */ @@ -1198,19 +1222,17 @@ emit_nat_info (struct unw_state_record *sr, int i, struct unw_script *script) struct unw_reg_info *r = sr->curr.reg + i; enum unw_insn_opcode opc; struct unw_insn insn; - unsigned long val; + unsigned long val = 0; switch (r->where) { case UNW_WHERE_GR: if (r->val >= 32) { /* register got spilled to a stacked register */ opc = UNW_INSN_SETNAT_TYPE; - val = UNW_NAT_STACKED; - } else { + val = UNW_NAT_REGSTK; + } else /* register got spilled to a scratch register */ - opc = UNW_INSN_SETNAT_TYPE; - val = UNW_NAT_SCRATCH; - } + opc = UNW_INSN_SETNAT_MEMSTK; break; case UNW_WHERE_FR: @@ -1225,8 +1247,7 @@ emit_nat_info (struct unw_state_record *sr, int i, struct unw_script *script) case UNW_WHERE_PSPREL: case UNW_WHERE_SPREL: - opc = UNW_INSN_SETNAT_PRI_UNAT; - val = 0; + opc = UNW_INSN_SETNAT_MEMSTK; break; default: @@ -1267,18 +1288,8 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script) } val = unw.preg_index[UNW_REG_R4 + (rval - 4)]; } else { - opc = UNW_INSN_LOAD_SPREL; - val = -sizeof(struct pt_regs); - if (rval >= 1 && rval <= 3) - val += struct_offset(struct pt_regs, r1) + 8*(rval - 1); - else if (rval <= 11) - val += struct_offset(struct pt_regs, r8) + 8*(rval - 8); - else if (rval <= 15) - val += struct_offset(struct pt_regs, r12) + 8*(rval - 12); - else if (rval <= 31) - val += struct_offset(struct pt_regs, r16) + 8*(rval - 16); - else - dprintk("unwind: bad scratch reg r%lu\n", rval); + opc = UNW_INSN_ADD_SP; + val = -sizeof(struct pt_regs) + pt_regs_off(rval); } break; @@ -1288,7 +1299,7 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script) else if (rval >= 16 && rval <= 31) val = unw.preg_index[UNW_REG_F16 + (rval - 16)]; else { - opc = UNW_INSN_LOAD_SPREL; + opc = UNW_INSN_ADD_SP; val = -sizeof(struct pt_regs); if (rval <= 9) val += struct_offset(struct pt_regs, f6) + 16*(rval - 6); @@ -1301,7 +1312,7 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script) if (rval >= 1 && rval <= 5) val = unw.preg_index[UNW_REG_B1 + (rval - 1)]; else { - opc = UNW_INSN_LOAD_SPREL; + opc = UNW_INSN_ADD_SP; val = -sizeof(struct pt_regs); if (rval == 0) val += struct_offset(struct pt_regs, b0); @@ -1313,11 +1324,11 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script) break; case UNW_WHERE_SPREL: - opc = UNW_INSN_LOAD_SPREL; + opc = UNW_INSN_ADD_SP; break; case UNW_WHERE_PSPREL: - opc = UNW_INSN_LOAD_PSPREL; + opc = UNW_INSN_ADD_PSP; break; default: @@ -1330,6 +1341,18 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script) script_emit(script, insn); if (need_nat_info) emit_nat_info(sr, i, script); + + if (i == UNW_REG_PSP) { + /* + * info->psp must contain the _value_ of the previous + * sp, not it's save location. We get this by + * dereferencing the value we just stored in + * info->psp: + */ + insn.opc = UNW_INSN_LOAD; + insn.dst = insn.val = unw.preg_index[UNW_REG_PSP]; + script_emit(script, insn); + } } static inline struct unw_table_entry * @@ -1378,7 +1401,7 @@ build_script (struct unw_frame_info *info) memset(&sr, 0, sizeof(sr)); for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) r->when = UNW_WHEN_NEVER; - sr.pr_val = info->pr_val; + sr.pr_val = info->pr; script = script_new(ip); if (!script) { @@ -1447,8 +1470,8 @@ build_script (struct unw_frame_info *info) } #if UNW_DEBUG - printk ("unwind: state record for func 0x%lx, t=%u:\n", - table->segment_base + e->start_offset, sr.when_target); + printk("unwind: state record for func 0x%lx, t=%u:\n", + table->segment_base + e->start_offset, sr.when_target); for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) { if (r->where != UNW_WHERE_NONE || r->when != UNW_WHEN_NEVER) { printk(" %s <- ", unw.preg_name[r - sr.curr.reg]); @@ -1463,7 +1486,7 @@ build_script (struct unw_frame_info *info) break; default: printk("BADWHERE(%d)", r->where); break; } - printk ("\t\t%d\n", r->when); + printk("\t\t%d\n", r->when); } } #endif @@ -1472,13 +1495,17 @@ build_script (struct unw_frame_info *info) /* translate state record into unwinder instructions: */ - if (sr.curr.reg[UNW_REG_PSP].where == UNW_WHERE_NONE - && sr.when_target > sr.curr.reg[UNW_REG_PSP].when && sr.curr.reg[UNW_REG_PSP].val != 0) - { + /* + * First, set psp if we're dealing with a fixed-size frame; + * subsequent instructions may depend on this value. + */ + if (sr.when_target > sr.curr.reg[UNW_REG_PSP].when + && (sr.curr.reg[UNW_REG_PSP].where == UNW_WHERE_NONE) + && sr.curr.reg[UNW_REG_PSP].val != 0) { /* new psp is sp plus frame size */ insn.opc = UNW_INSN_ADD; - insn.dst = unw.preg_index[UNW_REG_PSP]; - insn.val = sr.curr.reg[UNW_REG_PSP].val; + insn.dst = struct_offset(struct unw_frame_info, psp)/8; + insn.val = sr.curr.reg[UNW_REG_PSP].val; /* frame size */ script_emit(script, insn); } @@ -1562,23 +1589,34 @@ run_script (struct unw_script *script, struct unw_frame_info *state) val); break; - case UNW_INSN_LOAD_PSPREL: + case UNW_INSN_ADD_PSP: s[dst] = state->psp + val; break; - case UNW_INSN_LOAD_SPREL: + case UNW_INSN_ADD_SP: s[dst] = state->sp + val; break; - case UNW_INSN_SETNAT_PRI_UNAT: - if (!state->pri_unat) - state->pri_unat = &state->sw->caller_unat; - s[dst+1] = ((*state->pri_unat - s[dst]) << 32) | UNW_NAT_PRI_UNAT; + case UNW_INSN_SETNAT_MEMSTK: + if (!state->pri_unat_loc) + state->pri_unat_loc = &state->sw->ar_unat; + /* register off. is a multiple of 8, so the least 3 bits (type) are 0 */ + s[dst+1] = (*state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK; break; case UNW_INSN_SETNAT_TYPE: s[dst+1] = val; break; + + case UNW_INSN_LOAD: +#if UNW_DEBUG + if ((s[val] & (my_cpu_data.unimpl_va_mask | 0x7)) || s[val] < TASK_SIZE) { + debug(1, "unwind: rejecting bad psp=0x%lx\n", s[val]); + break; + } +#endif + s[dst] = *(unsigned long *) s[val]; + break; } } STAT(unw.stat.script.run_time += ia64_get_itc() - start); @@ -1587,13 +1625,14 @@ run_script (struct unw_script *script, struct unw_frame_info *state) lazy_init: off = unw.sw_off[val]; s[val] = (unsigned long) state->sw + off; - if (off >= struct_offset (struct unw_frame_info, r4) - && off <= struct_offset (struct unw_frame_info, r7)) + if (off >= struct_offset(struct switch_stack, r4) + && off <= struct_offset(struct switch_stack, r7)) /* - * We're initializing a general register: init NaT info, too. Note that we - * rely on the fact that call_unat is the first field in struct switch_stack: + * We're initializing a general register: init NaT info, too. Note that + * the offset is a multiple of 8 which gives us the 3 bits needed for + * the type field. */ - s[val+1] = (-off << 32) | UNW_NAT_PRI_UNAT; + s[val+1] = (struct_offset(struct switch_stack, ar_unat) - off) | UNW_NAT_MEMSTK; goto redo; } @@ -1603,11 +1642,10 @@ find_save_locs (struct unw_frame_info *info) int have_write_lock = 0; struct unw_script *scr; - if ((info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) || rgn_index(info->ip) != RGN_KERNEL) - { + if ((info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) { /* don't let obviously bad addresses pollute the cache */ debug(1, "unwind: rejecting bad ip=0x%lx\n", info->ip); - info->rp = 0; + info->rp_loc = 0; return -1; } @@ -1648,12 +1686,12 @@ unw_unwind (struct unw_frame_info *info) prev_bsp = info->bsp; /* restore the ip */ - if (!info->rp) { + if (!info->rp_loc) { 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; } - ip = info->ip = *info->rp; + ip = info->ip = *info->rp_loc; if (ip < GATE_ADDR + PAGE_SIZE) { /* * We don't have unwind info for the gate page, so we consider that part @@ -1665,23 +1703,23 @@ unw_unwind (struct unw_frame_info *info) } /* restore the cfm: */ - if (!info->pfs) { + if (!info->pfs_loc) { dprintk("unwind: failed to locate ar.pfs!\n"); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; } - info->cfm = info->pfs; + info->cfm_loc = info->pfs_loc; /* restore the bsp: */ - pr = info->pr_val; + pr = info->pr; num_regs = 0; if ((info->flags & UNW_FLAG_INTERRUPT_FRAME)) { if ((pr & (1UL << pNonSys)) != 0) - num_regs = *info->cfm & 0x7f; /* size of frame */ - info->pfs = + num_regs = *info->cfm_loc & 0x7f; /* size of frame */ + info->pfs_loc = (unsigned long *) (info->sp + 16 + struct_offset(struct pt_regs, ar_pfs)); } else - num_regs = (*info->cfm >> 7) & 0x7f; /* size of locals */ + num_regs = (*info->cfm_loc >> 7) & 0x7f; /* size of locals */ info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -num_regs); if (info->bsp < info->regstk.limit || info->bsp > info->regstk.top) { dprintk("unwind: bsp (0x%lx) out of range [0x%lx-0x%lx]\n", @@ -1694,7 +1732,7 @@ unw_unwind (struct unw_frame_info *info) info->sp = info->psp; if (info->sp < info->memstk.top || info->sp > info->memstk.limit) { dprintk("unwind: sp (0x%lx) out of range [0x%lx-0x%lx]\n", - info->sp, info->regstk.top, info->regstk.limit); + info->sp, info->memstk.top, info->memstk.limit); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; } @@ -1705,8 +1743,11 @@ unw_unwind (struct unw_frame_info *info) return -1; } + /* as we unwind, the saved ar.unat becomes the primary unat: */ + info->pri_unat_loc = info->unat_loc; + /* finally, restore the predicates: */ - unw_get_pr(info, &info->pr_val); + unw_get_pr(info, &info->pr); retval = find_save_locs(info); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); @@ -1773,11 +1814,11 @@ unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct info->task = t; info->sw = sw; info->sp = info->psp = (unsigned long) (sw + 1) - 16; - info->cfm = &sw->ar_pfs; - sol = (*info->cfm >> 7) & 0x7f; + info->cfm_loc = &sw->ar_pfs; + sol = (*info->cfm_loc >> 7) & 0x7f; info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol); info->ip = sw->b0; - info->pr_val = sw->pr; + info->pr = sw->pr; find_save_locs(info); STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags)); @@ -1808,7 +1849,7 @@ unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t) info->regstk.top = top; info->sw = sw; info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol); - info->cfm = &sw->ar_pfs; + info->cfm_loc = &sw->ar_pfs; info->ip = sw->b0; #endif } @@ -1845,7 +1886,7 @@ unw_init_from_current (struct unw_frame_info *info, struct pt_regs *regs) info->regstk.top = top; info->sw = sw; info->bsp = (unsigned long) ia64_rse_skip_regs(bsp, -sof); - info->cfm = ®s->cr_ifs; + info->cfm_loc = ®s->cr_ifs; info->ip = regs->cr_iip; #endif } @@ -1881,7 +1922,7 @@ read_reg (struct unw_frame_info *info, int regnum, int *is_nat) int unw_unwind (struct unw_frame_info *info) { - unsigned long sol, cfm = *info->cfm; + unsigned long sol, cfm = *info->cfm_loc; int is_nat; sol = (cfm >> 7) & 0x7f; /* size of locals */ @@ -1903,7 +1944,7 @@ unw_unwind (struct unw_frame_info *info) /* reject let obviously bad addresses */ return -1; - info->cfm = ia64_rse_skip_regs((unsigned long *) info->bsp, sol - 1); + info->cfm_loc = ia64_rse_skip_regs((unsigned long *) info->bsp, sol - 1); cfm = read_reg(info, sol - 1, &is_nat); if (is_nat) return -1; @@ -2006,7 +2047,7 @@ unw_remove_unwind_table (void *handle) if (prevt->next == table) break; if (!prevt) { - dprintk("unwind: failed to find unwind table %p\n", table); + dprintk("unwind: failed to find unwind table %p\n", (void *) table); spin_unlock_irqrestore(&unw.lock, flags); return; } @@ -2070,9 +2111,9 @@ unw_init (void) for (i = UNW_REG_F16, off = SW(F16); i <= UNW_REG_F31; ++i, off += 16) unw.sw_off[unw.preg_index[i]] = off; - unw.cache[0].coll_chain = -1; - for (i = 1; i < UNW_CACHE_SIZE; ++i) { - unw.cache[i].lru_chain = (i - 1); + for (i = 0; i < UNW_CACHE_SIZE; ++i) { + if (i > 0) + unw.cache[i].lru_chain = (i - 1); unw.cache[i].coll_chain = -1; unw.cache[i].lock = RW_LOCK_UNLOCKED; } diff --git a/arch/ia64/kernel/unwind_i.h b/arch/ia64/kernel/unwind_i.h index fea655efd..383d65eff 100644 --- a/arch/ia64/kernel/unwind_i.h +++ b/arch/ia64/kernel/unwind_i.h @@ -115,21 +115,21 @@ struct unw_state_record { enum unw_nat_type { UNW_NAT_NONE, /* NaT not represented */ UNW_NAT_VAL, /* NaT represented by NaT value (fp reg) */ - UNW_NAT_PRI_UNAT, /* NaT value is in unat word at offset OFF */ - UNW_NAT_SCRATCH, /* NaT value is in scratch.pri_unat */ - UNW_NAT_STACKED /* NaT is in rnat */ + UNW_NAT_MEMSTK, /* NaT value is in unat word at offset OFF */ + UNW_NAT_REGSTK /* NaT is in rnat */ }; enum unw_insn_opcode { UNW_INSN_ADD, /* s[dst] += val */ + UNW_INSN_ADD_PSP, /* s[dst] = (s.psp + val) */ + UNW_INSN_ADD_SP, /* s[dst] = (s.sp + val) */ UNW_INSN_MOVE, /* s[dst] = s[val] */ UNW_INSN_MOVE2, /* s[dst] = s[val]; s[dst+1] = s[val+1] */ UNW_INSN_MOVE_STACKED, /* s[dst] = ia64_rse_skip(*s.bsp, val) */ - UNW_INSN_LOAD_PSPREL, /* s[dst] = *(*s.psp + 8*val) */ - UNW_INSN_LOAD_SPREL, /* s[dst] = *(*s.sp + 8*val) */ - UNW_INSN_SETNAT_PRI_UNAT, /* s[dst+1].nat.type = PRI_UNAT; + UNW_INSN_SETNAT_MEMSTK, /* s[dst+1].nat.type = MEMSTK; s[dst+1].nat.off = *s.pri_unat - s[dst] */ - UNW_INSN_SETNAT_TYPE /* s[dst+1].nat.type = val */ + UNW_INSN_SETNAT_TYPE, /* s[dst+1].nat.type = val */ + UNW_INSN_LOAD /* s[dst] = *s[val] */ }; struct unw_insn { diff --git a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile index 318e314cc..90e697179 100644 --- a/arch/ia64/lib/Makefile +++ b/arch/ia64/lib/Makefile @@ -3,30 +3,49 @@ # .S.o: - $(CC) $(AFLAGS) -c $< -o $@ + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c $< -o $@ L_TARGET = lib.a -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 \ +L_OBJS = __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ + __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 strncpy_from_user.o strlen_user.o strnlen_user.o \ flush.o do_csum.o +ifneq ($(CONFIG_ITANIUM_ASTEP_SPECIFIC),y) + L_OBJS += memcpy.o memset.o strlen.o +endif + LX_OBJS = io.o -IGNORE_FLAGS_OBJS = __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o +IGNORE_FLAGS_OBJS = __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ + __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o -include $(TOPDIR)/Rules.make +$(L_TARGET): + +__divdi3.o: idiv64.S + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $@ $< + +__udivdi3.o: idiv64.S + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -DUNSIGNED -c -o $@ $< -__divdi3.o: idiv.S - $(CC) $(AFLAGS) -c -o $@ $< +__moddi3.o: idiv64.S + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -DMODULO -c -o $@ $< -__udivdi3.o: idiv.S - $(CC) $(AFLAGS) -c -DUNSIGNED -c -o $@ $< +__umoddi3.o: idiv64.S + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -DMODULO -DUNSIGNED -c -o $@ $< -__moddi3.o: idiv.S - $(CC) $(AFLAGS) -c -DMODULO -c -o $@ $< +__divsi3.o: idiv32.S + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $@ $< -__umoddi3.o: idiv.S - $(CC) $(AFLAGS) -c -DMODULO -DUNSIGNED -c -o $@ $< +__udivsi3.o: idiv32.S + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -DUNSIGNED -c -o $@ $< + +__modsi3.o: idiv32.S + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -DMODULO -c -o $@ $< + +__umodsi3.o: idiv32.S + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -DMODULO -DUNSIGNED -c -o $@ $< + +include $(TOPDIR)/Rules.make diff --git a/arch/ia64/lib/idiv32.S b/arch/ia64/lib/idiv32.S new file mode 100644 index 000000000..13f4608c3 --- /dev/null +++ b/arch/ia64/lib/idiv32.S @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2000 Hewlett-Packard Co + * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> + * + * 32-bit integer division. + * + * This code is based on the application note entitled "Divide, Square Root + * and Remainder Algorithms for the IA-64 Architecture". This document + * is available as Intel document number 248725-002 or via the web at + * http://developer.intel.com/software/opensource/numerics/ + * + * For more details on the theory behind these algorithms, see "IA-64 + * and Elementary Functions" by Peter Markstein; HP Professional Books + * (http://www.hp.com/go/retailbooks/) + */ + +#include <asm/asmmacro.h> + +#ifdef MODULO +# define OP mod +#else +# define OP div +#endif + +#ifdef UNSIGNED +# define SGN u +# define EXTEND zxt4 +# 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 EXTEND sxt4 +# define INT_TO_FP(a,b) fcvt.xf 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,si3)) + +GLOBAL_ENTRY(NAME) + .regstk 2,0,0,0 + // Transfer inputs to FP registers. + mov r2 = 0xffdd // r2 = -34 + 65535 (fp reg format bias) + EXTEND in0 = in0 // in0 = a + EXTEND in1 = in1 // in1 = b + ;; + setf.sig f8 = in0 + setf.sig f9 = in1 +#ifdef MODULO + sub in1 = r0, in1 // in1 = -b +#endif + ;; + // Convert the inputs to FP, to avoid FP software-assist faults. + INT_TO_FP(f8, f8) + INT_TO_FP(f9, f9) + ;; + setf.exp f7 = r2 // f7 = 2^-34 + frcpa.s1 f6, p6 = f8, f9 // y0 = frcpa(b) + ;; +(p6) fmpy.s1 f8 = f8, f6 // q0 = a*y0 +(p6) fnma.s1 f6 = f9, f6, f1 // e0 = -b*y0 + 1 + ;; +#ifdef MODULO + setf.sig f9 = in1 // f9 = -b +#endif +(p6) fma.s1 f8 = f6, f8, f8 // q1 = e0*q0 + q0 +(p6) fma.s1 f6 = f6, f6, f7 // e1 = e0*e0 + 2^-34 + ;; +#ifdef MODULO + setf.sig f7 = in0 +#endif +(p6) fma.s1 f6 = f6, f8, f8 // q2 = e1*q1 + q1 + ;; + FP_TO_INT(f6, f6) // q = trunc(q2) + ;; +#ifdef MODULO + xma.l f6 = f6, f9, f7 // r = q*(-b) + a + ;; +#endif + getf.sig r8 = f6 // transfer result to result register + br.ret.sptk rp +END(NAME) diff --git a/arch/ia64/lib/idiv.S b/arch/ia64/lib/idiv64.S index da96863d3..db7d2284e 100644 --- a/arch/ia64/lib/idiv.S +++ b/arch/ia64/lib/idiv64.S @@ -1,25 +1,21 @@ /* - * Integer division routine. - * * Copyright (C) 1999-2000 Hewlett-Packard Co * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> - */ - -#include <asm/asmmacro.h> - -/* - * 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. + * 64-bit integer division. * - * Must use max precision for the reciprocal computations to get 64 bits of - * precision. + * This code is based on the application note entitled "Divide, Square Root + * and Remainder Algorithms for the IA-64 Architecture". This document + * is available as Intel document number 248725-002 or via the web at + * http://developer.intel.com/software/opensource/numerics/ * - * r32 holds the dividend. r33 holds the divisor. + * For more details on the theory behind these algorithms, see "IA-64 + * and Elementary Functions" by Peter Markstein; HP Professional Books + * (http://www.hp.com/go/retailbooks/) */ +#include <asm/asmmacro.h> + #ifdef MODULO # define OP mod #else @@ -59,40 +55,38 @@ GLOBAL_ENTRY(NAME) UNW(.body) INT_TO_FP(f9, f9) ;; - frcpa.s1 f17, p6 = f8, f9 // y = frcpa(b) + frcpa.s1 f17, p6 = f8, f9 // y0 = 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) fmpy.s1 f7 = f8, f17 // q0 = a*y0 +(p6) fnma.s1 f6 = f9, f17, f1 // e0 = -b*y0 + 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 = f7, f6, f7 // q1 = q0*e0 + q0 +(p6) fmpy.s1 f7 = f6, f6 // e1 = e0*e0 ;; +#ifdef MODULO + sub in1 = r0, in1 // in1 = -b +#endif (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 = f17, f6, f17 // y1 = y0*e0 + y0 ;; (p6) fma.s1 f6 = f6, f7, f6 // y2 = y1*e1 + y1 (p6) fnma.s1 f7 = f9, f16, f8 // r = -b*q2 + a ;; -(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 - ;; + setf.sig f8 = in0 // f8 = a + setf.sig f9 = in1 // f9 = -b #endif +(p6) fma.s1 f17 = f7, f6, f16 // q3 = r*y2 + q2 + ;; UNW(.restore sp) ldf.fill f16 = [sp], 16 - FP_TO_INT(f8, f17) // round result to an (unsigned) integer + FP_TO_INT(f17, f17) // q = trunc(q3) ;; +#ifdef MODULO + xma.l f17 = f17, f9, f8 // r = q*(-b) + a + ;; +#endif + getf.sig r8 = f17 // transfer result to result register ldf.fill f17 = [sp] - getf.sig r8 = f8 // transfer result to result register br.ret.sptk rp END(NAME) diff --git a/arch/ia64/lib/io.c b/arch/ia64/lib/io.c index 466335172..baa408e01 100644 --- a/arch/ia64/lib/io.c +++ b/arch/ia64/lib/io.c @@ -1,4 +1,3 @@ -#include <linux/module.h> #include <linux/types.h> #include <asm/io.h> @@ -49,6 +48,3 @@ __ia64_memset_c_io (unsigned long dst, unsigned long c, long count) } } -EXPORT_SYMBOL(__ia64_memcpy_fromio); -EXPORT_SYMBOL(__ia64_memcpy_toio); -EXPORT_SYMBOL(__ia64_memset_c_io); diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 3652cfc80..b2cd880ad 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -357,6 +357,7 @@ ia64_rid_init (void) panic("mm/init: overlap between virtually mapped linear page table and " "mapped kernel space!"); pta = POW2(61) - POW2(impl_va_msb); +#ifndef CONFIG_DISABLE_VHPT /* * Set the (virtually mapped linear) page table address. Bit * 8 selects between the short and long format, bits 2-7 the @@ -364,6 +365,9 @@ ia64_rid_init (void) * enabled. */ ia64_set_pta(pta | (0<<8) | ((3*(PAGE_SHIFT-3)+3)<<2) | 1); +#else + ia64_set_pta(pta | (0<<8) | ((3*(PAGE_SHIFT-3)+3)<<2) | 0); +#endif } /* @@ -445,15 +449,6 @@ mem_init (void) /* install the gate page in the global page table: */ put_gate_page(virt_to_page(__start_gate_section), GATE_ADDR); -#ifndef CONFIG_IA64_SOFTSDV_HACKS - /* - * (Some) SoftSDVs seem to have a problem with this call. - * Since it's mostly a performance optimization, just don't do - * it for now... --davidm 99/12/6 - */ - efi_enter_virtual_mode(); -#endif - #ifdef CONFIG_IA32_SUPPORT ia32_gdt_init(); #endif diff --git a/arch/ia64/tools/Makefile b/arch/ia64/tools/Makefile index 0e6d78450..f98e2d1f3 100644 --- a/arch/ia64/tools/Makefile +++ b/arch/ia64/tools/Makefile @@ -46,4 +46,4 @@ print_offsets.s: print_offsets.c endif -.PHONY: all modules +.PHONY: all modules modules_install |