From mboxrd@z Thu Jan 1 00:00:00 1970 From: David Mosberger Date: Tue, 31 Oct 2000 08:55:03 +0000 Subject: [Linux-ia64] kernel update (relative to 2.4.0-test9) Message-Id: List-Id: References: In-Reply-To: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: linux-ia64@vger.kernel.org Here is a quick kernel update. I anticipate another update shortly after Linus releases test10. Thus, this patch hasn't received as much testing as I usually do. The kernel is known to work fine on 2P Big Sur and a slightly earlier version also worked fine on Lion and the simulator. As usual, YMMV. Summary of changes: - Asit & Goutham: fixed IOSAPIC support to work correctly when irq lines are shared by PCI devices - Asit: fix to unaligned access handler - Goutham: workaround for lost IPI problem - Don: IA-32 fixes & updates, in particular the beginnings of DRM support - Takayoshi: early-printk fixes to kernel startup code - Jun: optimized copy_user() for case where pointers are not co-aligned - Johannes: add VM_NONCACHED and VM_WRITECOMBINE for /dev/mem - Christophe: fixed unaligned accesses in Tulip (21140) NIC - BJ: update qla1280 driver to v3.19 - Intel: huge ACPI update (it's not in the diff below; go get the full patch to get this part) - Stephane: many performance related updates & fixes; in particular, the API is now entirely perfmonctl() based (no more ptrace() hacks needed) - drop platform_register_iosapic()---it's no longer needed - add workaround for potential ITC discontiguity - "backported" ftruncate() fix that caused kernel crash with certain filesystem stress tests - memcpy: tuned it some more - remove off workaround for unsorted unwind tables---it's no longer needed with the latest toolchain (thanks to Rich!) - separated IOSAPIC support from DIG, added some documentation, and restructured the code to make it (hopefully) more readable; also removed all (hard) IOSAPIC dependencies from acpi code - dropped BAD_ACPI_TABLE workaround; if you're still running old Lion firmware, this might bite you; if so, please upgrade the firmware (I don't think very many systems were shipped with the broken firmware, so I expect few if any people to be affected by this) - added AT_CLKTCK support for ELF binaries I hope I didn't miss anything. For the full patch, see: ftp://ftp.kernel.org/pub/linux/kernel/ports/ia64/ as usual. --david diff -urN linux-davidm/arch/ia64/dig/dig_irq.c lia64/arch/ia64/dig/dig_irq.c --- linux-davidm/arch/ia64/dig/dig_irq.c Wed Dec 31 16:00:00 1969 +++ lia64/arch/ia64/dig/dig_irq.c Mon Oct 30 23:40:05 2000 @@ -0,0 +1,10 @@ +void +dig_irq_init (void) +{ + /* + * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support + * enabled. + */ + outb(0xff, 0xA1); + outb(0xff, 0x21); +} diff -urN linux-davidm/arch/ia64/dig/iosapic.c lia64/arch/ia64/dig/iosapic.c --- linux-davidm/arch/ia64/dig/iosapic.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/dig/iosapic.c Wed Dec 31 16:00:00 1969 @@ -1,409 +0,0 @@ -/* - * Streamlined APIC support. - * - * Copyright (C) 1999 Intel Corp. - * Copyright (C) 1999 Asit Mallick - * Copyright (C) 1999-2000 Hewlett-Packard Co. - * Copyright (C) 1999-2000 David Mosberger-Tang - * Copyright (C) 1999 VA Linux Systems - * Copyright (C) 1999,2000 Walt Drummond - * - * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O APIC code. - * In particular, we now have separate handlers for edge - * and level triggered interrupts. - */ -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_ACPI_KERNEL_CONFIG -# include -#endif - -#undef DEBUG_IRQ_ROUTING - -static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED; - -struct iosapic_vector iosapic_vector[NR_IRQS] = { - [0 ... NR_IRQS-1] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } -}; - -/* - * find the IRQ in the IOSAPIC map for the PCI device on bus/slot/pin - */ -int -iosapic_get_PCI_irq_vector (int bus, int slot, int pci_pin) -{ - int i; - - for (i = 0; i < NR_IRQS; i++) { - if ((iosapic_bustype(i) = BUS_PCI) && - (iosapic_bus(i) = bus) && - (iosapic_busdata(i) = ((slot << 16) | pci_pin))) { - return i; - } - } - return -1; -} - -static void -set_rte (unsigned long iosapic_addr, int entry, int pol, int trigger, int delivery, - long dest, int vector) -{ - u32 low32; - u32 high32; - - low32 = ((pol << IO_SAPIC_POLARITY_SHIFT) | - (trigger << IO_SAPIC_TRIGGER_SHIFT) | - (delivery << IO_SAPIC_DELIVERY_SHIFT) | - vector); - -#ifdef CONFIG_IA64_AZUSA_HACKS - /* set Flush Disable bit */ - if (iosapic_addr != 0xc0000000fec00000) - low32 |= (1 << 17); -#endif - - /* dest contains both id and eid */ - high32 = (dest << IO_SAPIC_DEST_SHIFT); - - writel(IO_SAPIC_RTE_HIGH(entry), iosapic_addr + IO_SAPIC_REG_SELECT); - writel(high32, iosapic_addr + IO_SAPIC_WINDOW); - writel(IO_SAPIC_RTE_LOW(entry), iosapic_addr + IO_SAPIC_REG_SELECT); - writel(low32, iosapic_addr + IO_SAPIC_WINDOW); -} - -static void -nop (unsigned int irq) -{ - /* do nothing... */ -} - -static void -mask_irq (unsigned int irq) -{ - unsigned long flags, iosapic_addr = iosapic_addr(irq); - u32 low32; - - spin_lock_irqsave(&iosapic_lock, flags); - { - writel(IO_SAPIC_RTE_LOW(iosapic_pin(irq)), iosapic_addr + IO_SAPIC_REG_SELECT); - low32 = readl(iosapic_addr + IO_SAPIC_WINDOW); - - low32 |= (1 << IO_SAPIC_MASK_SHIFT); /* Zero only the mask bit */ - writel(low32, iosapic_addr + IO_SAPIC_WINDOW); - } - spin_unlock_irqrestore(&iosapic_lock, flags); -} - -static void -unmask_irq (unsigned int irq) -{ - unsigned long flags, iosapic_addr = iosapic_addr(irq); - u32 low32; - - spin_lock_irqsave(&iosapic_lock, flags); - { - writel(IO_SAPIC_RTE_LOW(iosapic_pin(irq)), iosapic_addr + IO_SAPIC_REG_SELECT); - low32 = readl(iosapic_addr + IO_SAPIC_WINDOW); - - low32 &= ~(1 << IO_SAPIC_MASK_SHIFT); /* Zero only the mask bit */ - writel(low32, iosapic_addr + IO_SAPIC_WINDOW); - } - spin_unlock_irqrestore(&iosapic_lock, flags); -} - - -static void -iosapic_set_affinity (unsigned int irq, unsigned long mask) -{ - printk("iosapic_set_affinity: not implemented yet\n"); -} - -/* - * Handlers for level-triggered interrupts. - */ - -static unsigned int -iosapic_startup_level_irq (unsigned int irq) -{ - unmask_irq(irq); - return 0; -} - -static void -iosapic_end_level_irq (unsigned int irq) -{ - writel(irq, iosapic_addr(irq) + IO_SAPIC_EOI); -} - -#define iosapic_shutdown_level_irq mask_irq -#define iosapic_enable_level_irq unmask_irq -#define iosapic_disable_level_irq mask_irq -#define iosapic_ack_level_irq nop - -struct hw_interrupt_type irq_type_iosapic_level = { - typename: "IO-SAPIC-level", - startup: iosapic_startup_level_irq, - shutdown: iosapic_shutdown_level_irq, - enable: iosapic_enable_level_irq, - disable: iosapic_disable_level_irq, - ack: iosapic_ack_level_irq, - end: iosapic_end_level_irq, - set_affinity: iosapic_set_affinity -}; - -/* - * Handlers for edge-triggered interrupts. - */ - -static unsigned int -iosapic_startup_edge_irq (unsigned int irq) -{ - unmask_irq(irq); - /* - * IOSAPIC simply drops interrupts pended while the - * corresponding pin was masked, so we can't know if an - * interrupt is pending already. Let's hope not... - */ - return 0; -} - -static void -iosapic_ack_edge_irq (unsigned int irq) -{ - /* - * Once we have recorded IRQ_PENDING already, we can mask the - * interrupt for real. This prevents IRQ storms from unhandled - * devices. - */ - if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) = (IRQ_PENDING | IRQ_DISABLED)) - mask_irq(irq); -} - -#define iosapic_enable_edge_irq unmask_irq -#define iosapic_disable_edge_irq nop -#define iosapic_end_edge_irq nop - -struct hw_interrupt_type irq_type_iosapic_edge = { - typename: "IO-SAPIC-edge", - startup: iosapic_startup_edge_irq, - shutdown: iosapic_disable_edge_irq, - enable: iosapic_enable_edge_irq, - disable: iosapic_disable_edge_irq, - ack: iosapic_ack_edge_irq, - end: iosapic_end_edge_irq, - set_affinity: iosapic_set_affinity -}; - -unsigned int -iosapic_version (unsigned long base_addr) -{ - /* - * IOSAPIC Version Register return 32 bit structure like: - * { - * unsigned int version : 8; - * unsigned int reserved1 : 8; - * unsigned int pins : 8; - * unsigned int reserved2 : 8; - * } - */ - writel(IO_SAPIC_VERSION, base_addr + IO_SAPIC_REG_SELECT); - return readl(IO_SAPIC_WINDOW + base_addr); -} - -void -iosapic_init (unsigned long address, int irqbase) -{ - struct hw_interrupt_type *irq_type; - struct pci_vector_struct *vectors; - int i, irq, num_pci_vectors; - - if (irqbase = 0) - /* - * Map the legacy ISA devices into the IOSAPIC data. - * Some of these may get reprogrammed later on with - * data from the ACPI Interrupt Source Override table. - */ - for (i = 0; i < 16; i++) { - irq = isa_irq_to_vector(i); - iosapic_pin(irq) = i; - iosapic_bus(irq) = BUS_ISA; - iosapic_busdata(irq) = 0; - iosapic_dmode(irq) = IO_SAPIC_LOWEST_PRIORITY; - iosapic_trigger(irq) = IO_SAPIC_EDGE; - iosapic_polarity(irq) = IO_SAPIC_POL_HIGH; -#ifdef DEBUG_IRQ_ROUTING - printk("ISA: IRQ %02x -> Vector %02x IOSAPIC Pin %d\n", - i, irq, iosapic_pin(irq)); -#endif - } - -#ifndef CONFIG_IA64_SOFTSDV_HACKS - /* - * 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; - 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); - if (iosapic_baseirq(irq) != irqbase) - continue; - - iosapic_bustype(irq) = BUS_PCI; - iosapic_pin(irq) = irq - iosapic_baseirq(irq); - iosapic_bus(irq) = vectors[i].bus; - /* - * Map the PCI slot and pin data into iosapic_busdata() - */ - iosapic_busdata(irq) = (vectors[i].pci_id & 0xffff0000) | vectors[i].pin; - - /* Default settings for PCI */ - iosapic_dmode(irq) = IO_SAPIC_LOWEST_PRIORITY; - iosapic_trigger(irq) = IO_SAPIC_LEVEL; - iosapic_polarity(irq) = IO_SAPIC_POL_LOW; - -# 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 /* CONFIG_IA64_SOFTSDV_HACKS */ - - for (i = 0; i < NR_IRQS; ++i) { - if (iosapic_baseirq(i) != irqbase) - continue; - - if (iosapic_pin(i) != -1) { - if (iosapic_trigger(i) = IO_SAPIC_LEVEL) - irq_type = &irq_type_iosapic_level; - else - irq_type = &irq_type_iosapic_edge; - if (irq_desc[i].handler != &no_irq_type) - printk("dig_irq_init: warning: changing vector %d from %s to %s\n", - i, irq_desc[i].handler->typename, - irq_type->typename); - irq_desc[i].handler = irq_type; - - /* program the IOSAPIC routing table: */ - set_rte(iosapic_addr(i), iosapic_pin(i), iosapic_polarity(i), - iosapic_trigger(i), iosapic_dmode(i), - (ia64_get_lid() >> 16) & 0xffff, i); - } - } -} - -void -dig_irq_init (void) -{ - /* - * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support - * enabled. - */ - outb(0xff, 0xA1); - outb(0xff, 0x21); -} - -void -dig_pci_fixup (void) -{ - struct pci_dev *dev; - int irq; - unsigned char pin; - - pci_for_each_dev(dev) { - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - if (pin) { - pin--; /* interrupt pins are numbered starting from 1 */ - irq = iosapic_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), - pin); - if (irq < 0 && dev->bus->parent) { /* go back to the bridge */ - struct pci_dev * bridge = dev->bus->self; - - /* allow for multiple bridges on an adapter */ - do { - /* do the bridge swizzle... */ - pin = (pin + PCI_SLOT(dev->devfn)) % 4; - irq = iosapic_get_PCI_irq_vector(bridge->bus->number, - PCI_SLOT(bridge->devfn), pin); - } while (irq < 0 && (bridge = bridge->bus->self)); - if (irq >= 0) - printk(KERN_WARNING - "PCI: using PPB(B%d,I%d,P%d) to get irq %02x\n", - bridge->bus->number, PCI_SLOT(bridge->devfn), - pin, irq); - else - printk(KERN_WARNING - "PCI: Couldn't map irq for B%d,I%d,P%d\n", - bridge->bus->number, PCI_SLOT(bridge->devfn), - pin); - } - if (irq >= 0) { - printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %02x\n", - dev->bus->number, PCI_SLOT(dev->devfn), pin, irq); - dev->irq = irq; - } - } - /* - * Nothing to fixup - * Fix out-of-range IRQ numbers - */ - if (dev->irq >= NR_IRQS) - dev->irq = 15; /* Spurious interrupts */ - } -} - -/* - * Register an IOSAPIC discovered via ACPI. - */ -void __init -dig_register_iosapic (acpi_entry_iosapic_t *iosapic) -{ - unsigned int ver, v; - int l, max_pin; - - ver = iosapic_version((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", - (ver & 0xf0) >> 4, (ver & 0x0f), iosapic->address, - iosapic->irq_base, iosapic->irq_base + max_pin); - - for (l = 0; l <= max_pin; l++) { - v = iosapic->irq_base + l; - if (v < 16) - v = isa_irq_to_vector(v); - if (v > IA64_MAX_VECTORED_IRQ) { - printk(" !!! bad IOSAPIC interrupt vector: %u\n", v); - continue; - } - /* XXX Check for IOSAPIC collisions */ - iosapic_addr(v) = (unsigned long) ioremap(iosapic->address, 0); - iosapic_baseirq(v) = iosapic->irq_base; - } - iosapic_init(iosapic->address, iosapic->irq_base); -} diff -urN linux-davidm/arch/ia64/dig/setup.c lia64/arch/ia64/dig/setup.c --- linux-davidm/arch/ia64/dig/setup.c Thu Aug 24 08:17:30 2000 +++ lia64/arch/ia64/dig/setup.c Mon Oct 30 22:28:55 2000 @@ -84,3 +84,14 @@ screen_info.orig_video_isVGA = 1; /* XXX fake */ screen_info.orig_video_ega_bx = 3; /* XXX fake */ } + +void +dig_irq_init (void) +{ + /* + * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support + * enabled. + */ + outb(0xff, 0xA1); + outb(0xff, 0x21); +} diff -urN linux-davidm/arch/ia64/ia32/binfmt_elf32.c lia64/arch/ia64/ia32/binfmt_elf32.c --- linux-davidm/arch/ia64/ia32/binfmt_elf32.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/ia32/binfmt_elf32.c Mon Oct 30 22:29:21 2000 @@ -9,6 +9,7 @@ #include +#include #include #include @@ -31,6 +32,9 @@ # define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE #endif +#undef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC IA32_CLOCKS_PER_SEC + extern void ia64_elf32_init(struct pt_regs *regs); extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address); @@ -239,6 +243,12 @@ if (eppnt->p_memsz >= (1UL<<32) || addr > (1UL<<32) - eppnt->p_memsz) return -EINVAL; + /* + * Make sure the elf interpreter doesn't get loaded at location 0 + * so that NULL pointers correctly cause segfaults. + */ + if (addr = 0) + addr += PAGE_SIZE; #if 1 set_brk(ia32_mm_addr(addr), addr + eppnt->p_memsz); memset((char *) addr + eppnt->p_filesz, 0, eppnt->p_memsz - eppnt->p_filesz); diff -urN linux-davidm/arch/ia64/ia32/ia32_entry.S lia64/arch/ia64/ia32/ia32_entry.S --- linux-davidm/arch/ia64/ia32/ia32_entry.S Fri Sep 8 14:34:53 2000 +++ lia64/arch/ia64/ia32/ia32_entry.S Mon Oct 30 22:29:33 2000 @@ -291,11 +291,43 @@ data8 sys_getcwd data8 sys_capget data8 sys_capset /* 185 */ - data8 sys_sigaltstack + data8 sys32_sigaltstack data8 sys_sendfile data8 sys32_ni_syscall /* streams1 */ data8 sys32_ni_syscall /* streams2 */ data8 sys32_vfork /* 190 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 195 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 200 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 205 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 210 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 215 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 220 */ + data8 sys_ni_syscall + data8 sys_ni_syscall /* * CAUTION: If any system calls are added beyond this point * then the check in `arch/ia64/kernel/ivt.S' will have diff -urN linux-davidm/arch/ia64/ia32/ia32_ioctl.c lia64/arch/ia64/ia32/ia32_ioctl.c --- linux-davidm/arch/ia64/ia32/ia32_ioctl.c Wed Aug 2 18:54:01 2000 +++ lia64/arch/ia64/ia32/ia32_ioctl.c Mon Oct 30 22:29:51 2000 @@ -22,81 +22,158 @@ #include #include #include +#include <../drivers/char/drm/drm.h> + +#define IOCTL_NR(a) ((a) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) + +#define DO_IOCTL(fd, cmd, arg) ({ \ + int _ret; \ + mm_segment_t _old_fs = get_fs(); \ + \ + set_fs(KERNEL_DS); \ + _ret = sys_ioctl(fd, cmd, (unsigned long)arg); \ + set_fs(_old_fs); \ + _ret; \ +}) + +#define P(i) ((void *)(long)(i)) + asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); asmlinkage long ia32_ioctl(unsigned int fd, unsigned int cmd, unsigned int arg) { + long ret; + + switch (IOCTL_NR(cmd)) { + + case IOCTL_NR(DRM_IOCTL_VERSION): + break; + case IOCTL_NR(DRM_IOCTL_GET_UNIQUE): + { + drm_unique_t un; + struct { + unsigned int unique_len; + unsigned int unique; + } un32; + + if (copy_from_user(&un32, P(arg), sizeof(un32))) + return -EFAULT; + un.unique_len = un32.unique_len; + un.unique = P(un32.unique); + ret = DO_IOCTL(fd, cmd, &un); + if (ret >= 0) { + un32.unique_len = un.unique_len; + if (copy_to_user(P(arg), &un32, sizeof(un32))) + return -EFAULT; + } + return(ret); + } + case IOCTL_NR(DRM_IOCTL_SET_UNIQUE): + case IOCTL_NR(DRM_IOCTL_ADD_MAP): + case IOCTL_NR(DRM_IOCTL_ADD_BUFS): + case IOCTL_NR(DRM_IOCTL_MARK_BUFS): + case IOCTL_NR(DRM_IOCTL_INFO_BUFS): + case IOCTL_NR(DRM_IOCTL_MAP_BUFS): + case IOCTL_NR(DRM_IOCTL_FREE_BUFS): + case IOCTL_NR(DRM_IOCTL_ADD_CTX): + case IOCTL_NR(DRM_IOCTL_RM_CTX): + case IOCTL_NR(DRM_IOCTL_MOD_CTX): + case IOCTL_NR(DRM_IOCTL_GET_CTX): + case IOCTL_NR(DRM_IOCTL_SWITCH_CTX): + case IOCTL_NR(DRM_IOCTL_NEW_CTX): + case IOCTL_NR(DRM_IOCTL_RES_CTX): + + case IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE): + case IOCTL_NR(DRM_IOCTL_AGP_RELEASE): + case IOCTL_NR(DRM_IOCTL_AGP_ENABLE): + case IOCTL_NR(DRM_IOCTL_AGP_INFO): + case IOCTL_NR(DRM_IOCTL_AGP_ALLOC): + case IOCTL_NR(DRM_IOCTL_AGP_FREE): + case IOCTL_NR(DRM_IOCTL_AGP_BIND): + case IOCTL_NR(DRM_IOCTL_AGP_UNBIND): + + /* Mga specific ioctls */ + + case IOCTL_NR(DRM_IOCTL_MGA_INIT): + + /* I810 specific ioctls */ + + case IOCTL_NR(DRM_IOCTL_I810_GETBUF): + case IOCTL_NR(DRM_IOCTL_I810_COPY): + + /* Rage 128 specific ioctls */ - switch (cmd) { + case IOCTL_NR(DRM_IOCTL_R128_PACKET): - case VFAT_IOCTL_READDIR_BOTH: - case VFAT_IOCTL_READDIR_SHORT: - case MTIOCGET: - case MTIOCPOS: - case MTIOCGETCONFIG: - case MTIOCSETCONFIG: - case PPPIOCSCOMPRESS: - case PPPIOCGIDLE: - case NCP_IOC_GET_FS_INFO_V2: - case NCP_IOC_GETOBJECTNAME: - case NCP_IOC_SETOBJECTNAME: - case NCP_IOC_GETPRIVATEDATA: - case NCP_IOC_SETPRIVATEDATA: - case NCP_IOC_GETMOUNTUID2: - case CAPI_MANUFACTURER_CMD: - case VIDIOCGTUNER: - case VIDIOCSTUNER: - case VIDIOCGWIN: - case VIDIOCSWIN: - case VIDIOCGFBUF: - case VIDIOCSFBUF: - case MGSL_IOCSPARAMS: - case MGSL_IOCGPARAMS: - case ATM_GETNAMES: - case ATM_GETLINKRATE: - case ATM_GETTYPE: - case ATM_GETESI: - case ATM_GETADDR: - case ATM_RSTADDR: - case ATM_ADDADDR: - case ATM_DELADDR: - case ATM_GETCIRANGE: - case ATM_SETCIRANGE: - case ATM_SETESI: - case ATM_SETESIF: - case ATM_GETSTAT: - case ATM_GETSTATZ: - case ATM_GETLOOP: - case ATM_SETLOOP: - case ATM_QUERYLOOP: - case ENI_SETMULT: - case NS_GETPSTAT: - /* case NS_SETBUFLEV: This is a duplicate case with ZATM_GETPOOLZ */ - case ZATM_GETPOOLZ: - case ZATM_GETPOOL: - case ZATM_SETPOOL: - case ZATM_GETTHIST: - case IDT77105_GETSTAT: - case IDT77105_GETSTATZ: - case IXJCTL_TONE_CADENCE: - case IXJCTL_FRAMES_READ: - case IXJCTL_FRAMES_WRITTEN: - case IXJCTL_READ_WAIT: - case IXJCTL_WRITE_WAIT: - case IXJCTL_DRYBUFFER_READ: - case I2OHRTGET: - case I2OLCTGET: - case I2OPARMSET: - case I2OPARMGET: - case I2OSWDL: - case I2OSWUL: - case I2OSWDEL: - case I2OHTML: - printk("%x:unimplemented IA32 ioctl system call\n", cmd); - return(-EINVAL); + case IOCTL_NR(VFAT_IOCTL_READDIR_BOTH): + case IOCTL_NR(VFAT_IOCTL_READDIR_SHORT): + case IOCTL_NR(MTIOCGET): + case IOCTL_NR(MTIOCPOS): + case IOCTL_NR(MTIOCGETCONFIG): + case IOCTL_NR(MTIOCSETCONFIG): + case IOCTL_NR(PPPIOCSCOMPRESS): + case IOCTL_NR(PPPIOCGIDLE): + case IOCTL_NR(NCP_IOC_GET_FS_INFO_V2): + case IOCTL_NR(NCP_IOC_GETOBJECTNAME): + case IOCTL_NR(NCP_IOC_SETOBJECTNAME): + case IOCTL_NR(NCP_IOC_GETPRIVATEDATA): + case IOCTL_NR(NCP_IOC_SETPRIVATEDATA): + case IOCTL_NR(NCP_IOC_GETMOUNTUID2): + case IOCTL_NR(CAPI_MANUFACTURER_CMD): + case IOCTL_NR(VIDIOCGTUNER): + case IOCTL_NR(VIDIOCSTUNER): + case IOCTL_NR(VIDIOCGWIN): + case IOCTL_NR(VIDIOCSWIN): + case IOCTL_NR(VIDIOCGFBUF): + case IOCTL_NR(VIDIOCSFBUF): + case IOCTL_NR(MGSL_IOCSPARAMS): + case IOCTL_NR(MGSL_IOCGPARAMS): + case IOCTL_NR(ATM_GETNAMES): + case IOCTL_NR(ATM_GETLINKRATE): + case IOCTL_NR(ATM_GETTYPE): + case IOCTL_NR(ATM_GETESI): + case IOCTL_NR(ATM_GETADDR): + case IOCTL_NR(ATM_RSTADDR): + case IOCTL_NR(ATM_ADDADDR): + case IOCTL_NR(ATM_DELADDR): + case IOCTL_NR(ATM_GETCIRANGE): + case IOCTL_NR(ATM_SETCIRANGE): + case IOCTL_NR(ATM_SETESI): + case IOCTL_NR(ATM_SETESIF): + case IOCTL_NR(ATM_GETSTAT): + case IOCTL_NR(ATM_GETSTATZ): + case IOCTL_NR(ATM_GETLOOP): + case IOCTL_NR(ATM_SETLOOP): + case IOCTL_NR(ATM_QUERYLOOP): + case IOCTL_NR(ENI_SETMULT): + case IOCTL_NR(NS_GETPSTAT): + /* case IOCTL_NR(NS_SETBUFLEV): This is a duplicate case with ZATM_GETPOOLZ */ + case IOCTL_NR(ZATM_GETPOOLZ): + case IOCTL_NR(ZATM_GETPOOL): + case IOCTL_NR(ZATM_SETPOOL): + case IOCTL_NR(ZATM_GETTHIST): + case IOCTL_NR(IDT77105_GETSTAT): + case IOCTL_NR(IDT77105_GETSTATZ): + case IOCTL_NR(IXJCTL_TONE_CADENCE): + case IOCTL_NR(IXJCTL_FRAMES_READ): + case IOCTL_NR(IXJCTL_FRAMES_WRITTEN): + case IOCTL_NR(IXJCTL_READ_WAIT): + case IOCTL_NR(IXJCTL_WRITE_WAIT): + case IOCTL_NR(IXJCTL_DRYBUFFER_READ): + case IOCTL_NR(I2OHRTGET): + case IOCTL_NR(I2OLCTGET): + case IOCTL_NR(I2OPARMSET): + case IOCTL_NR(I2OPARMGET): + case IOCTL_NR(I2OSWDL): + case IOCTL_NR(I2OSWUL): + case IOCTL_NR(I2OSWDEL): + case IOCTL_NR(I2OHTML): + break; default: return(sys_ioctl(fd, cmd, (unsigned long)arg)); } + printk("%x:unimplemented IA32 ioctl system call\n", cmd); + return(-EINVAL); } diff -urN linux-davidm/arch/ia64/ia32/ia32_traps.c lia64/arch/ia64/ia32/ia32_traps.c --- linux-davidm/arch/ia64/ia32/ia32_traps.c Thu Jun 22 07:09:44 2000 +++ lia64/arch/ia64/ia32/ia32_traps.c Mon Oct 30 22:30:04 2000 @@ -119,6 +119,6 @@ default: return -1; } - force_sig_info(SIGTRAP, &siginfo, current); + force_sig_info(siginfo.si_signo, &siginfo, current); return 0; } diff -urN linux-davidm/arch/ia64/ia32/sys_ia32.c lia64/arch/ia64/ia32/sys_ia32.c --- linux-davidm/arch/ia64/ia32/sys_ia32.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/ia32/sys_ia32.c Mon Oct 30 22:32:34 2000 @@ -236,8 +236,6 @@ if (OFFSET4K(addr) || OFFSET4K(off)) return -EINVAL; - if (prot & PROT_WRITE) - prot |= PROT_EXEC; prot |= PROT_WRITE; front = NULL; back = NULL; @@ -287,23 +285,20 @@ unsigned int poff; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + prot |= PROT_EXEC; if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK))) error = do_mmap_fake(file, addr, len, prot, flags, (loff_t)offset); - else if (!addr && (offset & ~PAGE_MASK)) { + else { poff = offset & PAGE_MASK; len += offset - poff; down(¤t->mm->mmap_sem); - error = do_mmap(file, addr, len, prot, flags, poff); + error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT); up(¤t->mm->mmap_sem); if (!IS_ERR((void *) error)) error += offset - poff; - } else { - down(¤t->mm->mmap_sem); - error = do_mmap(file, addr, len, prot, flags, offset); - up(¤t->mm->mmap_sem); } return error; } @@ -2032,14 +2027,14 @@ ret = sys_times(tbuf ? &t : NULL); set_fs (old_fs); if (tbuf) { - err = put_user (t.tms_utime, &tbuf->tms_utime); - err |= __put_user (t.tms_stime, &tbuf->tms_stime); - err |= __put_user (t.tms_cutime, &tbuf->tms_cutime); - err |= __put_user (t.tms_cstime, &tbuf->tms_cstime); + err = put_user (IA32_TICK(t.tms_utime), &tbuf->tms_utime); + err |= __put_user (IA32_TICK(t.tms_stime), &tbuf->tms_stime); + err |= __put_user (IA32_TICK(t.tms_cutime), &tbuf->tms_cutime); + err |= __put_user (IA32_TICK(t.tms_cstime), &tbuf->tms_cstime); if (err) ret = -EFAULT; } - return ret; + return IA32_TICK(ret); } unsigned int @@ -2617,6 +2612,45 @@ * manipulating the page protections... */ return(sys_iopl(3, 0, 0, 0)); +} + +typedef struct { + unsigned int ss_sp; + unsigned int ss_flags; + unsigned int ss_size; +} ia32_stack_t; + +asmlinkage long +sys32_sigaltstack (const ia32_stack_t *uss32, ia32_stack_t *uoss32, +long arg2, long arg3, long arg4, +long arg5, long arg6, long arg7, +long stack) +{ + struct pt_regs *pt = (struct pt_regs *) &stack; + stack_t uss, uoss; + ia32_stack_t buf32; + int ret; + mm_segment_t old_fs = get_fs(); + + if (uss32) + if (copy_from_user(&buf32, (void *)A(uss32), sizeof(ia32_stack_t))) + return(-EFAULT); + uss.ss_sp = buf32.ss_sp; + uss.ss_flags = buf32.ss_flags; + uss.ss_size = buf32.ss_size; + set_fs(KERNEL_DS); + ret = do_sigaltstack(uss32 ? &uss : NULL, &uoss, pt->r12); + set_fs(old_fs); + if (ret < 0) + return(ret); + if (uoss32) { + buf32.ss_sp = uoss.ss_sp; + buf32.ss_flags = uoss.ss_flags; + buf32.ss_size = uoss.ss_size; + if (copy_to_user((void*)A(uoss32), &buf32, sizeof(ia32_stack_t))) + return(-EFAULT); + } + return(ret); } #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ diff -urN linux-davidm/arch/ia64/kernel/Makefile lia64/arch/ia64/kernel/Makefile --- linux-davidm/arch/ia64/kernel/Makefile Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/Makefile Mon Oct 30 22:33:15 2000 @@ -13,7 +13,8 @@ machvec.o pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \ signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o -obj-$(CONFIG_IA64_GENERIC) += machvec.o +obj-$(CONFIG_IA64_GENERIC) += machvec.o iosapic.o +obj-$(CONFIG_IA64_DIG) += iosapic.o obj-$(CONFIG_IA64_PALINFO) += palinfo.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_SMP) += smp.o smpboot.o @@ -21,7 +22,7 @@ obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o O_TARGET := kernel.o -O_OBJS := $(obj-y) +O_OBJS := $(obj-y) OX_OBJS := ia64_ksyms.o clean:: diff -urN linux-davidm/arch/ia64/kernel/acpi.c lia64/arch/ia64/kernel/acpi.c --- linux-davidm/arch/ia64/kernel/acpi.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/acpi.c Mon Oct 30 22:33:27 2000 @@ -6,6 +6,8 @@ * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999,2000 Walt Drummond + * Copyright (C) 2000 Hewlett-Packard Co. + * Copyright (C) 2000 David Mosberger-Tang */ #include @@ -36,11 +38,14 @@ void (*pm_idle)(void); +asm (".weak iosapic_register_legacy_irq"); +asm (".weak iosapic_init"); + /* * Identify usable CPU's and remember them for SMP bringup later. */ static void __init -acpi_lsapic(char *p) +acpi_lsapic (char *p) { int add = 1; @@ -58,7 +63,7 @@ printk("Performance Restricted; ignoring.\n"); add = 0; } - + #ifdef CONFIG_SMP smp_boot_data.cpu_phys_id[total_cpus] = -1; #endif @@ -73,83 +78,40 @@ } /* - * Configure legacy IRQ information in iosapic_vector + * Configure legacy IRQ information. */ static void __init -acpi_legacy_irq(char *p) +acpi_legacy_irq (char *p) { - /* - * This is not good. ACPI is not necessarily limited to CONFIG_IA64_DIG, yet - * ACPI does not necessarily imply IOSAPIC either. Perhaps there should be - * a means for platform_setup() to register ACPI handlers? - */ -#ifdef CONFIG_IA64_IRQ_ACPI acpi_entry_int_override_t *legacy = (acpi_entry_int_override_t *) p; - unsigned char vector; - int i; - - vector = isa_irq_to_vector(legacy->isa_irq); + unsigned long polarity = 0, edge_triggered = 0; /* - * Clobber any old pin mapping. It may be that it gets replaced later on + * If the platform we're running doesn't define + * iosapic_register_legacy_irq(), we ignore this info... */ - for (i = 0; i < IA64_MAX_VECTORED_IRQ; i++) { - if (i = vector) - continue; - if (iosapic_pin(i) = iosapic_pin(vector)) - iosapic_pin(i) = 0xff; - } - - iosapic_pin(vector) = legacy->pin; - iosapic_bus(vector) = BUS_ISA; /* This table only overrides the ISA devices */ - iosapic_busdata(vector) = 0; - - /* - * External timer tick is special... - */ - if (vector != TIMER_IRQ) - iosapic_dmode(vector) = IO_SAPIC_LOWEST_PRIORITY; - else - iosapic_dmode(vector) = IO_SAPIC_FIXED; - + if (!iosapic_register_legacy_irq) + return; + /* See MPS 1.4 section 4.3.4 */ switch (legacy->flags) { - case 0x5: - iosapic_polarity(vector) = IO_SAPIC_POL_HIGH; - iosapic_trigger(vector) = IO_SAPIC_EDGE; - break; - case 0x8: - iosapic_polarity(vector) = IO_SAPIC_POL_LOW; - iosapic_trigger(vector) = IO_SAPIC_EDGE; - break; - case 0xd: - iosapic_polarity(vector) = IO_SAPIC_POL_HIGH; - iosapic_trigger(vector) = IO_SAPIC_LEVEL; - break; - case 0xf: - iosapic_polarity(vector) = IO_SAPIC_POL_LOW; - iosapic_trigger(vector) = IO_SAPIC_LEVEL; - break; - default: + case 0x5: polarity = 1; edge_triggered = 1; break; + case 0x8: polarity = 0; edge_triggered = 1; break; + case 0xd: polarity = 1; edge_triggered = 0; break; + case 0xf: polarity = 0; edge_triggered = 0; break; + default: printk(" ACPI Legacy IRQ 0x%02x: Unknown flags 0x%x\n", legacy->isa_irq, legacy->flags); break; } - -# 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 /* CONFIG_IA64_IRQ_ACPI */ + iosapic_register_legacy_irq(legacy->isa_irq, legacy->pin, polarity, edge_triggered); } /* * Info on platform interrupt sources: NMI. PMI, INIT, etc. */ static void __init -acpi_platform(char *p) +acpi_platform (char *p) { acpi_entry_platform_src_t *plat = (acpi_entry_platform_src_t *) p; @@ -161,8 +123,9 @@ * Parse the ACPI Multiple SAPIC Table */ static void __init -acpi_parse_msapic(acpi_sapic_t *msapic) +acpi_parse_msapic (acpi_sapic_t *msapic) { + acpi_entry_iosapic_t *iosapic; char *p, *end; /* Base address of IPI Message Block */ @@ -172,41 +135,31 @@ end = p + (msapic->header.length - sizeof(acpi_sapic_t)); while (p < end) { - switch (*p) { - case ACPI_ENTRY_LOCAL_SAPIC: + case ACPI_ENTRY_LOCAL_SAPIC: acpi_lsapic(p); break; - case ACPI_ENTRY_IO_SAPIC: - platform_register_iosapic((acpi_entry_iosapic_t *) p); + case ACPI_ENTRY_IO_SAPIC: + iosapic = (acpi_entry_iosapic_t *) p; + if (iosapic_init) + iosapic_init(iosapic->address, iosapic->irq_base); break; - case ACPI_ENTRY_INT_SRC_OVERRIDE: + case ACPI_ENTRY_INT_SRC_OVERRIDE: acpi_legacy_irq(p); break; - - case ACPI_ENTRY_PLATFORM_INT_SOURCE: + + case ACPI_ENTRY_PLATFORM_INT_SOURCE: acpi_platform(p); break; - - default: + + default: break; } /* Move to next table entry. */ -#define BAD_ACPI_TABLE -#ifdef BAD_ACPI_TABLE - /* - * Some prototype Lion's have a bad ACPI table - * requiring this fix. Without this fix, those - * machines crash during bootup. - */ - if (p[1] = 0) - p = end; - else -#endif - p += p[1]; + p += p[1]; } /* Make bootup pretty */ @@ -214,7 +167,7 @@ } int __init -acpi_parse(acpi_rsdp_t *rsdp) +acpi_parse (acpi_rsdp_t *rsdp) { acpi_rsdt_t *rsdt; acpi_desc_table_hdr_t *hdrp; @@ -256,7 +209,7 @@ } #ifdef CONFIG_ACPI_KERNEL_CONFIG - acpi_cf_terminate(); + acpi_cf_terminate(); #endif #ifdef CONFIG_SMP diff -urN linux-davidm/arch/ia64/kernel/efi.c lia64/arch/ia64/kernel/efi.c --- linux-davidm/arch/ia64/kernel/efi.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/efi.c Mon Oct 30 22:33:51 2000 @@ -363,7 +363,7 @@ #if EFI_DEBUG /* print EFI memory map: */ { - efi_memory_desc_t *md = p; + efi_memory_desc_t *md; void *p; for (i = 0, p = efi_map_start; p < efi_map_end; ++i, p += efi_desc_size) { diff -urN linux-davidm/arch/ia64/kernel/head.S lia64/arch/ia64/kernel/head.S --- linux-davidm/arch/ia64/kernel/head.S Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/head.S Mon Oct 30 22:34:49 2000 @@ -74,8 +74,8 @@ ;; #ifdef CONFIG_IA64_EARLY_PRINTK - mov r2=6 - mov r3=(8<<8) | (28<<2) + mov r3=(6<<8) | (28<<2) + movl r2=6<<61 ;; mov rr[r2]=r3 ;; @@ -181,7 +181,8 @@ GLOBAL_ENTRY(ia64_load_debug_regs) alloc r16=ar.pfs,1,0,0,0 -#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) +#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) lfetch.nta [in0] #endif mov r20=ar.lc // preserve ar.lc @@ -754,7 +755,7 @@ mov tmp=ar.itc (p15) br.cond.sptk .wait ;; - ld1 tmp=[r31] + ld4 tmp=[r31] ;; cmp.ne p15,p0=tmp,r0 mov tmp=ar.itc @@ -764,7 +765,7 @@ mov tmp=1 ;; IA64_SEMFIX_INSN - cmpxchg1.acq tmp=[r31],tmp,ar.ccv + cmpxchg4.acq tmp=[r31],tmp,ar.ccv ;; cmp.eq p15,p0=tmp,r0 diff -urN linux-davidm/arch/ia64/kernel/iosapic.c lia64/arch/ia64/kernel/iosapic.c --- linux-davidm/arch/ia64/kernel/iosapic.c Wed Dec 31 16:00:00 1969 +++ lia64/arch/ia64/kernel/iosapic.c Mon Oct 30 22:28:42 2000 @@ -0,0 +1,495 @@ +/* + * I/O SAPIC support. + * + * Copyright (C) 1999 Intel Corp. + * Copyright (C) 1999 Asit Mallick + * Copyright (C) 1999-2000 Hewlett-Packard Co. + * Copyright (C) 1999-2000 David Mosberger-Tang + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999,2000 Walt Drummond + * + * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O APIC code. + * In particular, we now have separate handlers for edge + * and level triggered interrupts. + * 00/10/27 Asit Mallick, Goutham Rao IRQ vector allocation + * PCI to vector mapping, shared PCI interrupts. + * 00/10/27 D. Mosberger Document things a bit more to make them more understandable. + * Clean up much of the old IOSAPIC cruft. + */ +/* + * Here is what the interrupt logic between a PCI device and the CPU looks like: + * + * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD). The + * device is uniquely identified by its bus-, device-, and slot-number (the function + * number does not matter here because all functions share the same interrupt + * lines). + * + * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller. + * Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level + * triggered and use the same polarity). Each interrupt line has a unique IOSAPIC + * irq number which can be calculated as the sum of the controller's base irq number + * and the IOSAPIC pin number to which the line connects. + * + * (3) The IOSAPIC uses an internal table to map the IOSAPIC pin into the IA-64 interrupt + * vector. This interrupt vector is then sent to the CPU. + * + * In other words, there are two levels of indirections involved: + * + * pci pin -> iosapic irq -> IA-64 vector + * + * Note: outside this module, IA-64 vectors are called "irqs". This is because that's + * the traditional name Linux uses for interrupt vectors. + */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ACPI_KERNEL_CONFIG +# include +#endif + +#undef DEBUG_IRQ_ROUTING + +static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED; + +/* PCI pin to IOSAPIC irq routing information. This info typically comes from ACPI. */ + +static struct { + int num_routes; + struct pci_vector_struct *route; +} pci_irq; + +/* This tables maps IA-64 vectors to the IOSAPIC pin that generates this vector. */ + +static struct iosapic_irq { + char *addr; /* base address of IOSAPIC */ + unsigned char base_irq; /* first irq assigned to this IOSAPIC */ + char pin; /* IOSAPIC pin (-1 => not an IOSAPIC irq) */ + unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ + unsigned char polarity : 1; /* interrupt polarity (see iosapic.h) */ + unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ +} iosapic_irq[NR_IRQS]; + +/* + * Translate IOSAPIC irq number to the corresponding IA-64 interrupt vector. If no + * entry exists, return -1. + */ +static int +iosapic_irq_to_vector (int irq) +{ + int vector; + + for (vector = 0; vector < NR_IRQS; ++vector) + if (iosapic_irq[vector].base_irq + iosapic_irq[vector].pin = irq) + return vector; + return -1; +} + +/* + * Map PCI pin to the corresponding IA-64 interrupt vector. If no such mapping exists, + * return -1. + */ +static int +pci_pin_to_vector (int bus, int slot, int pci_pin) +{ + struct pci_vector_struct *r; + + for (r = pci_irq.route; r < pci_irq.route + pci_irq.num_routes; ++r) + if (r->bus = bus && (r->pci_id >> 16) = slot && r->pin = pci_pin) + return iosapic_irq_to_vector(r->irq); + return -1; +} + +static void +set_rte (unsigned int vector, unsigned long dest) +{ + unsigned long pol, trigger, dmode; + u32 low32, high32; + char *addr; + int pin; + + pin = iosapic_irq[vector].pin; + if (pin < 0) + return; /* not an IOSAPIC interrupt */ + + addr = iosapic_irq[vector].addr; + pol = iosapic_irq[vector].polarity; + trigger = iosapic_irq[vector].trigger; + dmode = iosapic_irq[vector].dmode; + + low32 = ((pol << IOSAPIC_POLARITY_SHIFT) | + (trigger << IOSAPIC_TRIGGER_SHIFT) | + (dmode << IOSAPIC_DELIVERY_SHIFT) | + vector); + +#ifdef CONFIG_IA64_AZUSA_HACKS + /* set Flush Disable bit */ + if (addr != (char *) 0xc0000000fec00000) + low32 |= (1 << 17); +#endif + + /* dest contains both id and eid */ + high32 = (dest << IOSAPIC_DEST_SHIFT); + + writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT); + writel(high32, addr + IOSAPIC_WINDOW); + writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + writel(low32, addr + IOSAPIC_WINDOW); +} + +static void +nop (unsigned int vector) +{ + /* do nothing... */ +} + +static void +mask_irq (unsigned int vector) +{ + unsigned long flags; + char *addr; + u32 low32; + int pin; + + addr = iosapic_irq[vector].addr; + pin = iosapic_irq[vector].pin; + + if (pin < 0) + return; /* not an IOSAPIC interrupt! */ + + spin_lock_irqsave(&iosapic_lock, flags); + { + writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + low32 = readl(addr + IOSAPIC_WINDOW); + + low32 |= (1 << IOSAPIC_MASK_SHIFT); /* set only the mask bit */ + writel(low32, addr + IOSAPIC_WINDOW); + } + spin_unlock_irqrestore(&iosapic_lock, flags); +} + +static void +unmask_irq (unsigned int vector) +{ + unsigned long flags; + char *addr; + u32 low32; + int pin; + + addr = iosapic_irq[vector].addr; + pin = iosapic_irq[vector].pin; + if (pin < 0) + return; /* not an IOSAPIC interrupt! */ + + spin_lock_irqsave(&iosapic_lock, flags); + { + writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + low32 = readl(addr + IOSAPIC_WINDOW); + + low32 &= ~(1 << IOSAPIC_MASK_SHIFT); /* clear only the mask bit */ + writel(low32, addr + IOSAPIC_WINDOW); + } + spin_unlock_irqrestore(&iosapic_lock, flags); +} + + +static void +iosapic_set_affinity (unsigned int vector, unsigned long mask) +{ + printk("iosapic_set_affinity: not implemented yet\n"); +} + +/* + * Handlers for level-triggered interrupts. + */ + +static unsigned int +iosapic_startup_level_irq (unsigned int vector) +{ + unmask_irq(vector); + return 0; +} + +static void +iosapic_end_level_irq (unsigned int vector) +{ + writel(vector, iosapic_irq[vector].addr + IOSAPIC_EOI); +} + +#define iosapic_shutdown_level_irq mask_irq +#define iosapic_enable_level_irq unmask_irq +#define iosapic_disable_level_irq mask_irq +#define iosapic_ack_level_irq nop + +struct hw_interrupt_type irq_type_iosapic_level = { + typename: "IO-SAPIC-level", + startup: iosapic_startup_level_irq, + shutdown: iosapic_shutdown_level_irq, + enable: iosapic_enable_level_irq, + disable: iosapic_disable_level_irq, + ack: iosapic_ack_level_irq, + end: iosapic_end_level_irq, + set_affinity: iosapic_set_affinity +}; + +/* + * Handlers for edge-triggered interrupts. + */ + +static unsigned int +iosapic_startup_edge_irq (unsigned int vector) +{ + unmask_irq(vector); + /* + * IOSAPIC simply drops interrupts pended while the + * corresponding pin was masked, so we can't know if an + * interrupt is pending already. Let's hope not... + */ + return 0; +} + +static void +iosapic_ack_edge_irq (unsigned int vector) +{ + /* + * Once we have recorded IRQ_PENDING already, we can mask the + * interrupt for real. This prevents IRQ storms from unhandled + * devices. + */ + if ((irq_desc[vector].status & (IRQ_PENDING|IRQ_DISABLED)) = (IRQ_PENDING|IRQ_DISABLED)) + mask_irq(vector); +} + +#define iosapic_enable_edge_irq unmask_irq +#define iosapic_disable_edge_irq nop +#define iosapic_end_edge_irq nop + +struct hw_interrupt_type irq_type_iosapic_edge = { + typename: "IO-SAPIC-edge", + startup: iosapic_startup_edge_irq, + shutdown: iosapic_disable_edge_irq, + enable: iosapic_enable_edge_irq, + disable: iosapic_disable_edge_irq, + ack: iosapic_ack_edge_irq, + end: iosapic_end_edge_irq, + set_affinity: iosapic_set_affinity +}; + +static unsigned int +iosapic_version (char *addr) +{ + /* + * IOSAPIC Version Register return 32 bit structure like: + * { + * unsigned int version : 8; + * unsigned int reserved1 : 8; + * unsigned int pins : 8; + * unsigned int reserved2 : 8; + * } + */ + writel(IOSAPIC_VERSION, addr + IOSAPIC_REG_SELECT); + return readl(IOSAPIC_WINDOW + addr); +} + +/* + * ACPI calls this when it finds an entry for a legacy ISA interrupt. Note that the + * irq_base and IOSAPIC address must be set in iosapic_init(). + */ +void +iosapic_register_legacy_irq (unsigned long irq, + unsigned long pin, unsigned long polarity, + unsigned long edge_triggered) +{ + unsigned int vector = isa_irq_to_vector(irq); + +#ifdef DEBUG_IRQ_ROUTING + printk("ISA: IRQ %u -> IOSAPIC irq 0x%02x (%s, %s) -> vector %02x\n", + (unsigned) irq, (unsigned) pin, + polarity ? "high" : "low", edge_triggered ? "edge" : "level", + vector); +#endif + + iosapic_irq[vector].pin = pin; + iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY; + iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW; + iosapic_irq[vector].trigger = edge_triggered ? IOSAPIC_EDGE : IOSAPIC_LEVEL; +} + +void __init +iosapic_init (unsigned long phys_addr, unsigned int base_irq) +{ + struct hw_interrupt_type *irq_type; + int i, irq, max_pin, vector; + unsigned int ver; + char *addr; + static int first_time = 1; + + if (first_time) { + first_time = 0; + + for (vector = 0; vector < NR_IRQS; ++vector) + iosapic_irq[vector].pin = -1; /* mark as unused */ + + /* + * Fetch the PCI interrupt routing table: + */ +#ifdef CONFIG_ACPI_KERNEL_CONFIG + acpi_cf_get_pci_vectors(&pci_irq.route, &pci_irq.num_routes); +#else + pci_irq.route + (struct pci_vector_struct *) __va(ia64_boot_param.pci_vectors); + pci_irq.num_routes = ia64_boot_param.num_pci_vectors; +#endif + } + + addr = ioremap(phys_addr, 0); + + ver = iosapic_version(addr); + max_pin = (ver >> 16) & 0xff; + + printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n", + (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, base_irq, base_irq + max_pin); + + if (base_irq = 0) + /* + * Map the legacy ISA devices into the IOSAPIC data. Some of these may + * get reprogrammed later on with data from the ACPI Interrupt Source + * Override table. + */ + for (irq = 0; irq < 16; ++irq) { + vector = isa_irq_to_vector(irq); + iosapic_irq[vector].addr = addr; + iosapic_irq[vector].base_irq = 0; + if (iosapic_irq[vector].pin = -1) + iosapic_irq[vector].pin = irq; + iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY; + iosapic_irq[vector].trigger = IOSAPIC_EDGE; + iosapic_irq[vector].polarity = IOSAPIC_POL_HIGH; +#ifdef DEBUG_IRQ_ROUTING + printk("ISA: IRQ %u -> IOSAPIC irq 0x%02x (high, edge) -> vector 0x%02x\n", + irq, iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, + vector); +#endif + irq_type = &irq_type_iosapic_edge; + if (irq_desc[vector].handler != irq_type) { + if (irq_desc[vector].handler != &no_irq_type) + printk("iosapic_init: changing vector 0x%02x from %s to " + "%s\n", irq, irq_desc[vector].handler->typename, + irq_type->typename); + irq_desc[vector].handler = irq_type; + } + + /* program the IOSAPIC routing table: */ + set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); + } + +#ifndef CONFIG_IA64_SOFTSDV_HACKS + for (i = 0; i < pci_irq.num_routes; i++) { + irq = pci_irq.route[i].irq; + + if ((unsigned) (irq - base_irq) > max_pin) + /* the interrupt route is for another controller... */ + continue; + + if (irq < 16) + vector = isa_irq_to_vector(irq); + else { + vector = iosapic_irq_to_vector(irq); + if (vector < 0) + /* new iosapic irq: allocate a vector for it */ + vector = ia64_alloc_irq(); + } + + iosapic_irq[vector].addr = addr; + iosapic_irq[vector].base_irq = base_irq; + iosapic_irq[vector].pin = (irq - base_irq); + iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY; + iosapic_irq[vector].trigger = IOSAPIC_LEVEL; + iosapic_irq[vector].polarity = IOSAPIC_POL_LOW; + +# ifdef DEBUG_IRQ_ROUTING + printk("PCI: (B%d,I%d,P%d) -> IOSAPIC irq 0x%02x -> vector 0x%02x\n", + pci_irq.route[i].bus, pci_irq.route[i].pci_id>>16, pci_irq.route[i].pin, + iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector); +# endif + irq_type = &irq_type_iosapic_level; + if (irq_desc[vector].handler != irq_type){ + if (irq_desc[vector].handler != &no_irq_type) + printk("iosapic_init: changing vector 0x%02x from %s to %s\n", + vector, irq_desc[vector].handler->typename, + irq_type->typename); + irq_desc[vector].handler = irq_type; + } + + /* program the IOSAPIC routing table: */ + set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); + } +#endif /* !CONFIG_IA64_SOFTSDV_HACKS */ +} + +void +iosapic_pci_fixup (void) +{ + struct pci_dev *dev; + unsigned char pin; + int vector; + + pci_for_each_dev(dev) { + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (pin) { + pin--; /* interrupt pins are numbered starting from 1 */ + vector = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); + if (vector < 0 && dev->bus->parent) { + /* go back to the bridge */ + struct pci_dev *bridge = dev->bus->self; + + if (bridge) { + /* allow for multiple bridges on an adapter */ + do { + /* do the bridge swizzle... */ + pin = (pin + PCI_SLOT(dev->devfn)) % 4; + vector = pci_pin_to_vector(bridge->bus->number, + PCI_SLOT(bridge->devfn), + pin); + } while (vector < 0 && (bridge = bridge->bus->self)); + } + if (vector >= 0) + printk(KERN_WARNING + "PCI: using PPB(B%d,I%d,P%d) to get vector %02x\n", + bridge->bus->number, PCI_SLOT(bridge->devfn), + pin, vector); + else + printk(KERN_WARNING + "PCI: Couldn't map irq for (B%d,I%d,P%d)o\n", + bridge->bus->number, PCI_SLOT(bridge->devfn), + pin); + } + if (vector >= 0) { + printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> 0x%02x\n", + dev->bus->number, PCI_SLOT(dev->devfn), pin, vector); + dev->irq = vector; + } + } + /* + * Nothing to fixup + * Fix out-of-range IRQ numbers + */ + if (dev->irq >= NR_IRQS) + dev->irq = 15; /* Spurious interrupts */ + } +} diff -urN linux-davidm/arch/ia64/kernel/irq_ia64.c lia64/arch/ia64/kernel/irq_ia64.c --- linux-davidm/arch/ia64/kernel/irq_ia64.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/irq_ia64.c Mon Oct 30 22:35:56 2000 @@ -7,6 +7,9 @@ * * 6/10/99: Updated to bring in sync with x86 version to facilitate * support for SMP and different interrupt controllers. + * + * 09/15/00 Goutham Rao Implemented pci_irq_to_vector + * PCI to vector allocation routine. */ #include @@ -43,15 +46,25 @@ unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IPI_DEFAULT_BASE_ADDR); /* - * Legacy IRQ to IA-64 vector translation table. Any vector not in - * this table maps to itself (ie: irq 0x30 => IA64 vector 0x30) + * Legacy IRQ to IA-64 vector translation table. */ __u8 isa_irq_to_vector_map[16] = { /* 8259 IRQ translation, first 16 entries */ - 0x60, 0x50, 0x10, 0x51, 0x52, 0x53, 0x43, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x40, 0x41 + 0x2f, 0x20, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, + 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21 }; +int +ia64_alloc_irq (void) +{ + static int next_irq = FIRST_DEVICE_IRQ; + + if (next_irq > LAST_DEVICE_IRQ) + /* XXX could look for sharable vectors instead of panic'ing... */ + panic("ia64_alloc_irq: out of interrupt vectors!"); + return next_irq++; +} + #ifdef CONFIG_ITANIUM_A1_SPECIFIC int usbfix; @@ -217,7 +230,7 @@ } void -ipi_send (int cpu, int vector, int delivery_mode, int redirect) +ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect) { unsigned long ipi_addr; unsigned long ipi_data; diff -urN linux-davidm/arch/ia64/kernel/ivt.S lia64/arch/ia64/kernel/ivt.S --- linux-davidm/arch/ia64/kernel/ivt.S Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/ivt.S Tue Oct 31 00:02:02 2000 @@ -924,7 +924,7 @@ alloc r15=ar.pfs,0,0,6,0 // must first in an insn group ;; ld4 r8=[r14],8 // r8 = EAX (syscall number) - mov r150 // sys_vfork - last implemented system call + mov r15"2 // sys_vfork - last implemented system call ;; cmp.leu.unc p6,p7=r8,r15 ld4 out1=[r14],8 // r9 = ecx diff -urN linux-davidm/arch/ia64/kernel/mca.c lia64/arch/ia64/kernel/mca.c --- linux-davidm/arch/ia64/kernel/mca.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/mca.c Mon Oct 30 23:56:26 2000 @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -365,7 +366,7 @@ void ia64_mca_wakeup(int cpu) { - ipi_send(cpu, IA64_MCA_WAKEUP_INT_VECTOR, IA64_IPI_DM_INT, 0); + ia64_send_ipi(cpu, IA64_MCA_WAKEUP_INT_VECTOR, IA64_IPI_DM_INT, 0); ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; } diff -urN linux-davidm/arch/ia64/kernel/pci.c lia64/arch/ia64/kernel/pci.c --- linux-davidm/arch/ia64/kernel/pci.c Thu Jun 22 07:09:44 2000 +++ lia64/arch/ia64/kernel/pci.c Mon Oct 30 22:36:54 2000 @@ -56,7 +56,8 @@ /* Macro to build a PCI configuration address to be passed as a parameter to SAL. */ -#define PCI_CONFIG_ADDRESS(dev, where) (((u64) dev->bus->number << 16) | ((u64) (dev->devfn & 0xff) << 8) | (where & 0xff)) +#define PCI_CONFIG_ADDRESS(dev, where) \ + (((u64) dev->bus->number << 16) | ((u64) (dev->devfn & 0xff) << 8) | (where & 0xff)) static int pci_conf_read_config_byte(struct pci_dev *dev, int where, u8 *value) @@ -109,7 +110,6 @@ return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 4, value); } - static struct pci_ops pci_conf = { pci_conf_read_config_byte, pci_conf_read_config_word, @@ -120,35 +120,18 @@ }; /* - * Try to find PCI BIOS. This will always work for IA64. - */ - -static struct pci_ops * __init -pci_find_bios(void) -{ - return &pci_conf; -} - -/* * Initialization. Uses the SAL interface */ - -#define PCI_BUSES_TO_SCAN 255 - void __init pcibios_init(void) { +# define PCI_BUSES_TO_SCAN 255 struct pci_ops *ops = NULL; int i; - if ((ops = pci_find_bios()) = NULL) { - printk("PCI: No PCI bus detected\n"); - return; - } - printk("PCI: Probing PCI hardware\n"); for (i = 0; i < PCI_BUSES_TO_SCAN; i++) - pci_scan_bus(i, ops, NULL); + pci_scan_bus(i, &pci_conf, NULL); platform_pci_fixup(); return; } @@ -157,7 +140,6 @@ * Called after each bus is probed, but before its children * are examined. */ - void __init pcibios_fixup_bus(struct pci_bus *b) { @@ -207,7 +189,6 @@ /* * PCI BIOS setup, always defaults to SAL interface */ - char * __init pcibios_setup(char *str) { diff -urN linux-davidm/arch/ia64/kernel/perfmon.c lia64/arch/ia64/kernel/perfmon.c --- linux-davidm/arch/ia64/kernel/perfmon.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/perfmon.c Mon Oct 30 22:37:23 2000 @@ -4,18 +4,20 @@ * * Originaly Written by Ganesh Venkitachalam, IBM Corp. * Modifications by David Mosberger-Tang, Hewlett-Packard Co. + * Modifications by Stephane Eranian, Hewlett-Packard Co. * Copyright (C) 1999 Ganesh Venkitachalam * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 2000 Stephane Eranian */ #include + #include #include #include #include #include #include -#include #include #include @@ -58,19 +60,51 @@ #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 PFM_WRITE_PMCS 0xa0 +#define PFM_WRITE_PMDS 0xa1 +#define PFM_READ_PMDS 0xa2 +#define PFM_STOP 0xa3 +#define PFM_START 0xa4 +#define PFM_ENABLE 0xa5 /* unfreeze only */ +#define PFM_DISABLE 0xa6 /* freeze only */ +/* + * Those 2 are just meant for debugging. I considered using sysctl() for + * that but it is a little bit too pervasive. This solution is at least + * self-contained. + */ +#define PFM_DEBUG_ON 0xe0 +#define PFM_DEBUG_OFF 0xe1 + +#ifdef CONFIG_SMP +#define cpu_is_online(i) (cpu_online_map & (1UL << i)) +#else +#define cpu_is_online(i) 1 +#endif +#define PMC_IS_IMPL(i) (pmu_conf.impl_regs[i>>6] & (1<< (i&~(64-1)))) +#define PMD_IS_IMPL(i) (pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1)))) +#define PMD_IS_COUNTER(i) (i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters)) +#define PMC_IS_COUNTER(i) (i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters)) /* * this structure needs to be enhanced */ typedef struct { + unsigned long pfr_reg_num; /* which register */ + unsigned long pfr_reg_value; /* configuration (PMC) or initial value (PMD) */ + unsigned long pfr_reg_reset; /* reset value on overflow (PMD) */ + void *pfr_smpl_buf; /* pointer to user buffer for EAR/BTB */ + unsigned long pfr_smpl_size; /* size of user buffer for EAR/BTB */ + pid_t pfr_notify_pid; /* process to notify */ + int pfr_notify_sig; /* signal for notification, 0=no notification */ +} perfmon_req_t; + +#if 0 +typedef struct { unsigned long pmu_reg_data; /* generic PMD register */ unsigned long pmu_reg_num; /* which register number */ } perfmon_reg_t; +#endif /* * This structure is initialize at boot time and contains @@ -78,86 +112,141 @@ * 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) */ + unsigned long perf_ovfl_val; /* overflow value for generic counters */ + unsigned long max_counters; /* upper limit on counter pair (PMC/PMD) */ + unsigned long impl_regs[16]; /* buffer used to hold implememted PMC/PMD mask */ } 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; +/* for debug only */ +static unsigned long pfm_debug=1; /* 0= nodebug, >0= debug output on */ +#define DBprintk(a) {\ + if (pfm_debug >0) { printk a; } \ +} + /* - * could optimize to avoid cache conflicts in SMP + * could optimize to avoid cache line conflicts in SMP */ -unsigned long pmds[NR_CPUS][MAX_PERF_COUNTER]; +static struct task_struct *pmu_owners[NR_CPUS]; -asmlinkage unsigned long -sys_perfmonctl (int cmd, int count, void *ptr, long arg4, long arg5, long arg6, long arg7, long arg8, long stack) +static int +do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, int count, struct pt_regs *regs) { - struct pt_regs *regs = (struct pt_regs *) &stack; - perfmon_reg_t tmp, *cptr = ptr; - unsigned long cnum; + perfmon_req_t tmp; int i; switch (cmd) { - case WRITE_PMCS: /* Writes to PMC's and clears PMDs */ - case WRITE_PMCS_AND_START: /* Also starts counting */ + case PFM_WRITE_PMCS: + /* we don't quite support this right now */ + if (task != current) return -EINVAL; + + if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; + + for (i = 0; i < count; i++, req++) { + copy_from_user(&tmp, req, sizeof(tmp)); + + /* XXX needs to check validity of the data maybe */ + + if (!PMC_IS_IMPL(tmp.pfr_reg_num)) { + DBprintk((__FUNCTION__ " invalid pmc[%ld]\n", tmp.pfr_reg_num)); + return -EINVAL; + } + + /* XXX: for counters, need to some checks */ + if (PMC_IS_COUNTER(tmp.pfr_reg_num)) { + current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].sig = tmp.pfr_notify_sig; + current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].pid = tmp.pfr_notify_pid; + + DBprintk((__FUNCTION__" setting PMC[%ld] send sig %d to %d\n",tmp.pfr_reg_num, tmp.pfr_notify_sig, tmp.pfr_notify_pid)); + } + ia64_set_pmc(tmp.pfr_reg_num, tmp.pfr_reg_value); + + DBprintk((__FUNCTION__" setting PMC[%ld]=0x%lx\n", tmp.pfr_reg_num, tmp.pfr_reg_value)); + } + /* + * we have to set this here event hough we haven't necessarily started monitoring + * because we may be context switched out + */ + current->thread.flags |= IA64_THREAD_PM_VALID; + break; + + case PFM_WRITE_PMDS: + /* we don't quite support this right now */ + if (task != current) return -EINVAL; + + if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; + + for (i = 0; i < count; i++, req++) { + copy_from_user(&tmp, req, sizeof(tmp)); + + if (!PMD_IS_IMPL(tmp.pfr_reg_num)) return -EINVAL; + + /* update virtualized (64bits) counter */ + if (PMD_IS_COUNTER(tmp.pfr_reg_num)) { + current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].val = tmp.pfr_reg_value & ~pmu_conf.perf_ovfl_val; + current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].rval = tmp.pfr_reg_reset; + } + /* writes to unimplemented part is ignored, so this is safe */ + ia64_set_pmd(tmp.pfr_reg_num, tmp.pfr_reg_value); + /* to go away */ + ia64_srlz_d(); + DBprintk((__FUNCTION__" setting PMD[%ld]: pmod.val=0x%lx pmd=0x%lx rval=0x%lx\n", tmp.pfr_reg_num, current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].val, ia64_get_pmd(tmp.pfr_reg_num),current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].rval)); + } + /* + * we have to set this here event hough we haven't necessarily started monitoring + * because we may be context switched out + */ + current->thread.flags |= IA64_THREAD_PM_VALID; + break; + + case PFM_START: + /* we don't quite support this right now */ + if (task != current) return -EINVAL; - if (!access_ok(VERIFY_READ, cptr, sizeof(struct perfmon_reg_t)*count)) - return -EFAULT; + pmu_owners[smp_processor_id()] = current; - for (i = 0; i < count; i++, cptr++) { + /* will start monitoring right after rfi */ + ia64_psr(regs)->up = 1; - copy_from_user(&tmp, cptr, sizeof(tmp)); + /* + * mark the state as valid. + * this will trigger save/restore at context switch + */ + current->thread.flags |= IA64_THREAD_PM_VALID; - /* XXX need to check validity of pmu_reg_num and perhaps data!! */ + ia64_set_pmc(0, 0); - if (tmp.pmu_reg_num > pmu_conf.max_pmc || tmp.pmu_reg_num = 0) return -EFAULT; + break; - ia64_set_pmc(tmp.pmu_reg_num, tmp.pmu_reg_data); + case PFM_ENABLE: + /* we don't quite support this right now */ + if (task != current) return -EINVAL; - /* 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; + pmu_owners[smp_processor_id()] = current; - 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 (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 + /* + * mark the state as valid. + * this will trigger save/restore at context switch + */ + current->thread.flags |= IA64_THREAD_PM_VALID; + /* simply unfreeze */ ia64_set_pmc(0, 0); + break; - /* 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 (count <= 0 || count > MAX_PERF_COUNTER) - return -EINVAL; - if (!access_ok(VERIFY_WRITE, cptr, sizeof(struct perfmon_reg_t)*count)) - return -EFAULT; + case PFM_DISABLE: + /* we don't quite support this right now */ + if (task != current) return -EINVAL; + + /* simply unfreeze */ + ia64_set_pmc(0, 1); + ia64_srlz_d(); + break; + + case PFM_READ_PMDS: + if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; + if (!access_ok(VERIFY_WRITE, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; /* This looks shady, but IMHO this will work fine. This is * the sequence that I could come up with to avoid races @@ -187,16 +276,31 @@ * is the irq_save/restore needed? */ + for (i = 0; i < count; i++, req++) { + unsigned long val=0; - /* XXX: This needs to change to read more than just the counters */ - for (i = 0, cnum = PMU_FIRST_COUNTER;i < count; i++, cnum++, cptr++) { + copy_from_user(&tmp, req, sizeof(tmp)); - tmp.pmu_reg_data = (pmds[smp_processor_id()][i] - + (ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val)); + if (!PMD_IS_IMPL(tmp.pfr_reg_num)) return -EINVAL; - tmp.pmu_reg_num = cnum; + if (PMD_IS_COUNTER(tmp.pfr_reg_num)) { + if (task = current){ + val = ia64_get_pmd(tmp.pfr_reg_num) & pmu_conf.perf_ovfl_val; + } else { + val = task->thread.pmd[tmp.pfr_reg_num - PMU_FIRST_COUNTER] & pmu_conf.perf_ovfl_val; + } + val += task->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].val; + } else { + /* for now */ + if (task != current) return -EINVAL; + + val = ia64_get_pmd(tmp.pfr_reg_num); + } + tmp.pfr_reg_value = val; - if (copy_to_user(cptr, &tmp, sizeof(tmp))) return -EFAULT; +DBprintk((__FUNCTION__" reading PMD[%ld]=0x%lx\n", tmp.pfr_reg_num, val)); + + if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; } #if 0 /* irrelevant with user monitors */ @@ -209,11 +313,18 @@ #endif break; - case STOP_PMCS: + case PFM_STOP: + /* we don't quite support this right now */ + if (task != current) return -EINVAL; + ia64_set_pmc(0, 1); ia64_srlz_d(); - for (i = 0; i < MAX_PERF_COUNTER; ++i) - ia64_set_pmc(4+i, 0); + + ia64_psr(regs)->up = 0; + + current->thread.flags &= ~IA64_THREAD_PM_VALID; + + pmu_owners[smp_processor_id()] = NULL; #if 0 /* irrelevant with user monitors */ @@ -225,48 +336,140 @@ ia64_psr(regs)->up = 0; #endif - current->thread.flags &= ~(IA64_THREAD_PM_VALID); - break; + case PFM_DEBUG_ON: + printk(__FUNCTION__" debuggin on\n"); + pfm_debug = 1; + break; + + case PFM_DEBUG_OFF: + printk(__FUNCTION__" debuggin off\n"); + pfm_debug = 0; + break; + default: + DBprintk((__FUNCTION__" UNknown command 0x%x\n", cmd)); return -EINVAL; break; } return 0; } -static inline void -update_counters (void) +asmlinkage int +sys_perfmonctl (int pid, int cmd, int flags, perfmon_req_t *req, int count, long arg6, long arg7, long arg8, long stack) { - unsigned long mask, i, cnum, val; + struct pt_regs *regs = (struct pt_regs *) &stack; + struct task_struct *child = current; + int ret; - mask = ia64_get_pmc(0) >> 4; - for (i = 0, cnum = PMU_FIRST_COUNTER ; i < pmu_conf.max_counters; cnum++, i++, mask >>= 1) { + if (pid != current->pid) { + read_lock(&tasklist_lock); + { + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + } + if (!child) { + read_unlock(&tasklist_lock); + return -ESRCH; + } + /* + * XXX: need to do more checking here + */ + if (child->state != TASK_ZOMBIE) { + DBprintk((__FUNCTION__" warning process %d not in stable state %ld\n", pid, child->state)); + } + } + ret = do_perfmonctl(child, cmd, flags, req, count, regs); + if (child != current) read_unlock(&tasklist_lock); - val = mask & 0x1 ? pmu_conf.perf_ovfl_val + 1 : 0; + return ret; +} - if (mask & 0x1) - 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) & pmu_conf.perf_ovfl_val; +static inline int +update_counters (u64 pmc0) +{ + unsigned long mask, i, cnum; + struct thread_struct *th; + struct task_struct *ta; + + if (pmu_owners[smp_processor_id()] = NULL) { + DBprintk((__FUNCTION__" Spurious overflow interrupt: PMU not owned\n")); + return 0; + } + + /* + * It is never safe to access the task for which the overflow interrupt is destinated + * using the current variable as the interrupt may occur in the middle of a context switch + * where current does not hold the task that is running yet. + * + * For monitoring, however, we do need to get access to the task which caused the overflow + * to account for overflow on the counters. + * We accomplish this by maintaining a current owner of the PMU per CPU. During context + * switch the ownership is changed in a way such that the reflected owner is always the + * valid one, i.e. the one that caused the interrupt. + */ + ta = pmu_owners[smp_processor_id()]; + th = &pmu_owners[smp_processor_id()]->thread; - printk(__FUNCTION__ " adding val=%lx to pmod[%ld]=%lx \n", val, i, pmds[smp_processor_id()][i]); + /* + * Don't think this could happen given first test. Keep as sanity check + */ + if ((th->flags & IA64_THREAD_PM_VALID) = 0) { + DBprintk((__FUNCTION__" Spurious overflow interrupt: process %d not using perfmon\n", ta->pid)); + return 0; + } + + /* + * if PMU not frozen: spurious from previous context + * if PMC[0] = 0x1 : frozen but no overflow reported: leftover from previous context + * + * in either case we don't touch the state upon return from handler + */ + if ((pmc0 & 0x1) = 0 || pmc0 = 0x1) { + DBprintk((__FUNCTION__" Spurious overflow interrupt: process %d freeze=0\n",ta->pid)); + return 0; + } - pmds[smp_processor_id()][i] += val; + mask = pmc0 >> 4; - ia64_set_pmd(cnum, 0); + for (i = 0, cnum = PMU_FIRST_COUNTER; i < pmu_conf.max_counters; cnum++, i++, mask >>= 1) { + + if (mask & 0x1) { + DBprintk((__FUNCTION__ " PMD[%ld] overflowed pmd=0x%lx pmod.val=0x%lx\n", cnum, ia64_get_pmd(cnum), th->pmu_counters[i].val)); + + /* + * Because we somtimes (EARS/BTB) reset to a specific value, we cannot simply use + * val to count the number of times we overflowed. Otherwise we would loose the value + * current in the PMD (which can be >0). So to make sure we don't loose + * the residual counts we set val to contain full 64bits value of the counter. + */ + th->pmu_counters[i].val += 1+pmu_conf.perf_ovfl_val+(ia64_get_pmd(cnum) &pmu_conf.perf_ovfl_val); + + /* writes to upper part are ignored, so this is safe */ + ia64_set_pmd(cnum, th->pmu_counters[i].rval); + + DBprintk((__FUNCTION__ " pmod[%ld].val=0x%lx pmd=0x%lx\n", i, th->pmu_counters[i].val, ia64_get_pmd(cnum)&pmu_conf.perf_ovfl_val)); + + if (th->pmu_counters[i].pid != 0 && th->pmu_counters[i].sig>0) { + DBprintk((__FUNCTION__ " shouild notify process %d with signal %d\n",th->pmu_counters[i].pid, th->pmu_counters[i].sig)); + } + } } + return 1; } static void perfmon_interrupt (int irq, void *arg, struct pt_regs *regs) { - update_counters(); - ia64_set_pmc(0, 0); - ia64_srlz_d(); + /* unfreeze if not spurious */ + if ( update_counters(ia64_get_pmc(0)) ) { + ia64_set_pmc(0, 0); + ia64_srlz_d(); + } } static struct irqaction perfmon_irqaction = { @@ -280,9 +483,13 @@ { char *p = page; u64 pmc0 = ia64_get_pmc(0); + int i; - p += sprintf(p, "PMC[0]=%lx\n", pmc0); - + p += sprintf(p, "PMC[0]=%lx\nPerfmon debug: %s\n", pmc0, pfm_debug ? "On" : "Off"); + for(i=0; i < NR_CPUS; i++) { + if (cpu_is_online(i)) + p += sprintf(p, "CPU%d.PMU %d\n", i, pmu_owners[i] ? pmu_owners[i]->pid: -1); + } return p - page; } @@ -308,7 +515,6 @@ 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; @@ -320,15 +526,13 @@ printk("perfmon: Initialized vector to %u\n",PERFMON_IRQ); - if ((status=ia64_pal_perf_mon_info(pm_buffer, &pm_info)) != 0) { + if ((status=ia64_pal_perf_mon_info(pmu_conf.impl_regs, &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; + pmu_conf.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); @@ -347,36 +551,137 @@ ia64_srlz_d(); } +/* + * XXX: for system wide this function MUST never be called + */ void -ia64_save_pm_regs (struct thread_struct *t) +ia64_save_pm_regs (struct task_struct *ta) { - int i; + struct thread_struct *t = &ta->thread; + u64 pmc0, psr; + int i,j; + + /* + * We must maek sure that we don't loose any potential overflow + * interrupt while saving PMU context. In this code, external + * interrupts are always enabled. + */ + + /* + * save current PSR: needed because we modify it + */ + __asm__ __volatile__ ("mov %0=psr;;": "=r"(psr) :: "memory"); + + /* + * stop monitoring: + * This is the only way to stop monitoring without destroying overflow + * information in PMC[0..3]. + * This is the last instruction which can cause overflow when monitoring + * in kernel. + * By now, we could still have an overflow interrupt in flight. + */ + __asm__ __volatile__ ("rsm psr.up;;"::: "memory"); + + /* + * read current overflow status: + * + * We may be reading stale information at this point, if we got interrupt + * just before the read(pmc0) but that's all right. However, if we did + * not get the interrupt before, this read reflects LAST state. + * + */ + pmc0 = ia64_get_pmc(0); + /* + * freeze PMU: + * + * This destroys the overflow information. This is required to make sure + * next process does not start with monitoring on if not requested + * (PSR.up may not be enough). + * + * We could still get an overflow interrupt by now. However the handler + * will not do anything if is sees PMC[0].fr=1 but no overflow bits + * are set. So PMU will stay in frozen state. This implies that pmc0 + * will still be holding the correct unprocessed information. + * + */ ia64_set_pmc(0, 1); ia64_srlz_d(); + + /* + * check for overflow bits set: + * + * If pmc0 reports PMU frozen, this means we have a pending overflow, + * therefore we invoke the handler. Handler is reentrant with regards + * to PMC[0] so it is safe to call it twice. + * + * IF pmc0 reports overflow, we need to reread current PMC[0] value + * in case the handler was invoked right after the first pmc0 read. + * it is was not invoked then pmc0=PMC[0], otherwise it's been invoked + * and overflow information has been processed, so we don't need to call. + * + * Test breakdown: + * - pmc0 & ~0x1: test if overflow happened + * - second part: check if current register reflects this as well. + * + * NOTE: testing for pmc0 & 0x1 is not enough has it would trigger call + * when PM_VALID and PMU.fr which is common when setting up registers + * just before actually starting monitors. + * + */ + if ((pmc0 & ~0x1) && ((pmc0=ia64_get_pmc(0)) &~0x1) ) { + printk(__FUNCTION__" Warning: pmc[0]=0x%lx\n", pmc0); + update_counters(pmc0); + /* + * XXX: not sure that's enough. the next task may still get the + * interrupt. + */ + } + + /* + * restore PSR for context switch to save + */ + __asm__ __volatile__ ("mov psr.l=%0;;"::"r"(psr): "memory"); + /* * 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); + for (i=0,j=4; i< IA64_NUM_PMD_COUNTERS; i++,j++) { + t->pmd[i] = ia64_get_pmd(j); + t->pmc[i] = ia64_get_pmc(j); } + /* + * PMU is frozen, PMU context is saved: nobody owns the PMU on this CPU + * At this point, we should not receive any pending interrupt from the + * 'switched out' task + */ + pmu_owners[smp_processor_id()] = NULL; } void -ia64_load_pm_regs (struct thread_struct *t) +ia64_load_pm_regs (struct task_struct *ta) { - int i; + struct thread_struct *t = &ta->thread; + int i,j; + + /* + * we first restore ownership of the PMU to the 'soon to be current' + * context. This way, if, as soon as we unfreeze the PMU at the end + * of this function, we get an interrupt, we attribute it to the correct + * task + */ + pmu_owners[smp_processor_id()] = ta; /* * 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]); + for (i=0,j=4; i< IA64_NUM_PMD_COUNTERS; i++,j++) { + ia64_set_pmd(j, t->pmd[i]); + ia64_set_pmc(j, t->pmc[i]); } + /* + * unfreeze PMU + */ ia64_set_pmc(0, 0); ia64_srlz_d(); } diff -urN linux-davidm/arch/ia64/kernel/process.c lia64/arch/ia64/kernel/process.c --- linux-davidm/arch/ia64/kernel/process.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/process.c Mon Oct 30 22:38:03 2000 @@ -164,7 +164,7 @@ ia64_save_debug_regs(&task->thread.dbr[0]); #ifdef CONFIG_PERFMON if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) - ia64_save_pm_regs(&task->thread); + ia64_save_pm_regs(task); #endif if (IS_IA32_PROCESS(ia64_task_regs(task))) ia32_save_state(&task->thread); @@ -177,7 +177,7 @@ ia64_load_debug_regs(&task->thread.dbr[0]); #ifdef CONFIG_PERFMON if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) - ia64_load_pm_regs(&task->thread); + ia64_load_pm_regs(task); #endif if (IS_IA32_PROCESS(ia64_task_regs(task))) ia32_load_state(&task->thread); @@ -299,6 +299,14 @@ # define THREAD_FLAGS_TO_SET 0 p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR) | THREAD_FLAGS_TO_SET); +#ifdef CONFIG_IA32_SUPPORT + /* + * If we're cloning an IA32 task then save the IA32 extra + * state from the current task to the new task + */ + if (IS_IA32_PROCESS(ia64_task_regs(current))) + ia32_save_state(&p->thread); +#endif return 0; } @@ -554,7 +562,7 @@ * we garantee no race. this call we also stop * monitoring */ - ia64_save_pm_regs(¤t->thread); + ia64_save_pm_regs(current); /* * make sure that switch_to() will not save context again */ diff -urN linux-davidm/arch/ia64/kernel/ptrace.c lia64/arch/ia64/kernel/ptrace.c --- linux-davidm/arch/ia64/kernel/ptrace.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/ptrace.c Mon Oct 30 22:38:17 2000 @@ -794,11 +794,7 @@ addr); return -1; } - } else -#ifdef CONFIG_PERFMON - if (addr < PT_PMD) -#endif - { + } else { /* access debug registers */ if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { @@ -820,33 +816,14 @@ } 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; + if (write_access) + /* don't let the user set kernel-level breakpoints... */ + *ptr = *data & ~(7UL << 56); + else + *data = *ptr; + return 0; } -#endif if (write_access) *ptr = *data; else @@ -977,11 +954,7 @@ /* disallow accessing anything else... */ return -1; } - } else -#ifdef CONFIG_PERFMON - if (addr < PT_PMD) -#endif - { + } else { /* access debug registers */ @@ -1002,34 +975,14 @@ return -1; 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; + if (write_access) + /* don't let the user set kernel-level breakpoints... */ + *ptr = *data & ~(7UL << 56); + else + *data = *ptr; + return 0; } -#endif - if (write_access) *ptr = *data; else diff -urN linux-davidm/arch/ia64/kernel/smp.c lia64/arch/ia64/kernel/smp.c --- linux-davidm/arch/ia64/kernel/smp.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/smp.c Mon Oct 30 23:57:04 2000 @@ -11,6 +11,8 @@ * 00/03/31 Rohit Seth 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. + * 10/13/00 Goutham Rao Updated smp_call_function and + * smp_call_function_single to resend IPI on timeouts */ #define __KERNEL_SYSCALLS__ @@ -30,6 +32,7 @@ #include #include #include +#include #include #include @@ -276,7 +279,7 @@ return; set_bit(op, &ipi_op[dest_cpu]); - ipi_send(dest_cpu, IPI_IRQ, IA64_IPI_DM_INT, 0); + ia64_send_ipi(dest_cpu, IPI_IRQ, IA64_IPI_DM_INT, 0); } static inline void @@ -358,6 +361,7 @@ if (pointer_lock(&smp_call_function_data, &data, retry)) return -EBUSY; +resend: /* Send a message to all other CPUs and wait for them to respond */ send_IPI_single(cpuid, IPI_CALL_FUNC); @@ -366,8 +370,12 @@ while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout)) barrier(); if (atomic_read(&data.unstarted_count) > 0) { +#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) + goto resend; +#else smp_call_function_data = NULL; return -ETIMEDOUT; +#endif } if (wait) while (atomic_read(&data.unfinished_count) > 0) @@ -411,13 +419,23 @@ /* Send a message to all other CPUs and wait for them to respond */ send_IPI_allbutself(IPI_CALL_FUNC); +retry: /* Wait for response */ timeout = jiffies + HZ; while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout)) barrier(); if (atomic_read(&data.unstarted_count) > 0) { +#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) + int i; + for (i = 0; i < smp_num_cpus; i++) { + if (i != smp_processor_id()) + ia64_send_ipi(i, IPI_IRQ, IA64_IPI_DM_INT, 0); + } + goto retry; +#else smp_call_function_data = NULL; return -ETIMEDOUT; +#endif } if (wait) while (atomic_read(&data.unfinished_count) > 0) @@ -569,7 +587,7 @@ cpu_now_booting = cpu; /* Kick the AP in the butt */ - ipi_send(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); + ia64_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); /* wait up to 10s for the AP to start */ for (timeout = 0; timeout < 100000; timeout++) { diff -urN linux-davidm/arch/ia64/kernel/traps.c lia64/arch/ia64/kernel/traps.c --- linux-davidm/arch/ia64/kernel/traps.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/traps.c Mon Oct 30 22:40:14 2000 @@ -544,7 +544,7 @@ case 46: printk("Unexpected IA-32 intercept trap (Trap 46)\n"); - printk(" iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n", regs->cr_iip, ifa, isr); + printk(" iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n", regs->cr_iip, ifa, isr, iim); force_sig(SIGSEGV, current); return; diff -urN linux-davidm/arch/ia64/kernel/unaligned.c lia64/arch/ia64/kernel/unaligned.c --- linux-davidm/arch/ia64/kernel/unaligned.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/unaligned.c Mon Oct 30 22:40:27 2000 @@ -572,7 +572,8 @@ */ if (regnum = 0) { *val = 0; - *nat = 0; + if (nat) + *nat = 0; return; } diff -urN linux-davidm/arch/ia64/kernel/unwind.c lia64/arch/ia64/kernel/unwind.c --- linux-davidm/arch/ia64/kernel/unwind.c Mon Oct 30 23:54:13 2000 +++ lia64/arch/ia64/kernel/unwind.c Mon Oct 30 22:40:45 2000 @@ -46,16 +46,6 @@ #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define p5 5 -/* - * The unwind tables are supposed to be sorted, but the GNU toolchain - * currently fails to produce a sorted table in the presence of - * functions that go into sections other than .text. For example, the - * kernel likes to put initialization code into .text.init, which - * messes up the sort order. Hopefully, this will get fixed sometime - * soon. --davidm 00/05/23 - */ -#define UNWIND_TABLE_SORT_BUG - #define UNW_LOG_CACHE_SIZE 7 /* each unw_script is ~256 bytes in size */ #define UNW_CACHE_SIZE (1 << UNW_LOG_CACHE_SIZE) @@ -63,7 +53,7 @@ #define UNW_HASH_SIZE (1 << UNW_LOG_HASH_SIZE) #define UNW_DEBUG 0 -#define UNW_STATS 0 /* WARNING: this disabled interrupts for long time-spans!! */ +#define UNW_STATS 1 /* WARNING: this disabled interrupts for long time-spans!! */ #if UNW_DEBUG static long unw_debug_level = 255; @@ -1964,23 +1954,6 @@ { struct unw_table_entry *start = table_start, *end = table_end; -#ifdef UNWIND_TABLE_SORT_BUG - { - struct unw_table_entry *e1, *e2, tmp; - - /* stupid bubble sort... */ - - for (e1 = start; e1 < end; ++e1) { - for (e2 = e1 + 1; e2 < end; ++e2) { - if (e2->start_offset < e1->start_offset) { - tmp = *e1; - *e1 = *e2; - *e2 = tmp; - } - } - } - } -#endif table->name = name; table->segment_base = segment_base; table->gp = gp; diff -urN linux-davidm/arch/ia64/lib/copy_user.S lia64/arch/ia64/lib/copy_user.S --- linux-davidm/arch/ia64/lib/copy_user.S Wed Aug 2 18:54:02 2000 +++ lia64/arch/ia64/lib/copy_user.S Mon Oct 30 23:45:16 2000 @@ -65,6 +65,12 @@ // // local registers // +#define t1 r2 // rshift in bytes +#define t2 r3 // lshift in bytes +#define rshift r14 // right shift in bits +#define lshift r15 // left shift in bits +#define word1 r16 +#define word2 r17 #define cnt r18 #define len2 r19 #define saved_lc r20 @@ -134,6 +140,190 @@ br.ret.sptk.few rp // end of short memcpy // + // Not 8-byte aligned + // +diff_align_copy_user: + // At this point we know we have more than 16 bytes to copy + // and also that src and dest do _not_ have the same alignment. + and src2=0x7,src1 // src offset + and dst2=0x7,dst1 // dst offset + ;; + // The basic idea is that we copy byte-by-byte at the head so + // that we can reach 8-byte alignment for both src1 and dst1. + // Then copy the body using software pipelined 8-byte copy, + // shifting the two back-to-back words right and left, then copy + // the tail by copying byte-by-byte. + // + // Fault handling. If the byte-by-byte at the head fails on the + // load, then restart and finish the pipleline by copying zeros + // to the dst1. Then copy zeros for the rest of dst1. + // If 8-byte software pipeline fails on the load, do the same as + // failure_in3 does. If the byte-by-byte at the tail fails, it is + // handled simply by failure_in_pipe1. + // + // The case p14 represents the source has more bytes in the + // the first word (by the shifted part), whereas the p15 needs to + // copy some bytes from the 2nd word of the source that has the + // tail of the 1st of the destination. + // + + // + // Optimization. If dst1 is 8-byte aligned (not rarely), we don't need + // to copy the head to dst1, to start 8-byte copy software pipleline. + // We know src1 is not 8-byte aligned in this case. + // + cmp.eq p14,p15=r0,dst2 +(p15) br.cond.spnt.few 1f + ;; + sub t1=8,src2 + mov t2=src2 + ;; + shl rshift=t2,3 + sub len1=len,t1 // set len1 + ;; + sub lshiftd,rshift + ;; + br.cond.spnt.few word_copy_user + ;; +1: + cmp.leu p14,p15=src2,dst2 + sub t1=dst2,src2 + ;; + .pred.rel "mutex", p14, p15 +(p14) sub word1=8,src2 // (8 - src offset) +(p15) sub t1=r0,t1 // absolute value +(p15) sub word1=8,dst2 // (8 - dst offset) + ;; + // For the case p14, we don't need to copy the shifted part to + // the 1st word of destination. + sub t2=8,t1 +(p14) sub word1=word1,t1 + ;; + sub len1=len,word1 // resulting len +(p15) shl rshift=t1,3 // in bits +(p14) shl rshift=t2,3 + ;; +(p14) sub len1=len1,t1 + adds cnt=-1,word1 + ;; + sub lshiftd,rshift + mov ar.ec=PIPE_DEPTH + mov pr.rot=1<<16 // p16=true all others are false + mov ar.lc=cnt + ;; +2: + EX(failure_in_pipe2,(p16) ld1 val1[0]=[src1],1) + ;; + EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) + br.ctop.dptk.few 2b + ;; + clrrrb + ;; +word_copy_user: + cmp.gtu p9,p0,len1 +(p9) br.cond.spnt.few 4f // if (16 > len1) skip 8-byte copy + ;; + shr.u cnt=len1,3 // number of 64-bit words + ;; + adds cnt=-1,cnt + ;; + .pred.rel "mutex", p14, p15 +(p14) sub src1=src1,t2 +(p15) sub src1=src1,t1 + // + // Now both src1 and dst1 point to an 8-byte aligned address. And + // we have more than 8 bytes to copy. + // + mov ar.lc=cnt + mov ar.ec=PIPE_DEPTH + mov pr.rot=1<<16 // p16=true all others are false + ;; +3: + // + // The pipleline consists of 3 stages: + // 1 (p16): Load a word from src1 + // 2 (EPI_1): Shift right pair, saving to tmp + // 3 (EPI): Store tmp to dst1 + // + // To make it simple, use at least 2 (p16) loops to set up val1[n] + // because we need 2 back-to-back val1[] to get tmp. + // Note that this implies EPI_2 must be p18 or greater. + // + +#define EPI_1 p[PIPE_DEPTH-2] +#define SWITCH(pred, shift) cmp.eq pred,p0=shift,rshift +#define CASE(pred, shift) \ + (pred) br.cond.spnt.few copy_user_bit##shift +#define BODY(rshift) \ +copy_user_bit##rshift: \ +1: \ + EX(failure_out,(EPI) st8 [dst1]=tmp,8); \ +(EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift; \ + EX(failure_in2,(p16) ld8 val1[0]=[src1],8); \ + br.ctop.dptk.few 1b; \ + ;; \ + br.cond.spnt.few .diff_align_do_tail + + // + // Since the instruction 'shrp' requires a fixed 128-bit value + // specifying the bits to shift, we need to provide 7 cases + // below. + // + SWITCH(p6, 8) + SWITCH(p7, 16) + SWITCH(p8, 24) + SWITCH(p9, 32) + SWITCH(p10, 40) + SWITCH(p11, 48) + SWITCH(p12, 56) + ;; + CASE(p6, 8) + CASE(p7, 16) + CASE(p8, 24) + CASE(p9, 32) + CASE(p10, 40) + CASE(p11, 48) + CASE(p12, 56) + ;; + BODY(8) + BODY(16) + BODY(24) + BODY(32) + BODY(40) + BODY(48) + BODY(56) + ;; +.diff_align_do_tail: + .pred.rel "mutex", p14, p15 +(p14) sub src1=src1,t1 +(p14) adds dst1=-8,dst1 +(p15) sub dst1=dst1,t1 + ;; +4: + // Tail correction. + // + // The problem with this piplelined loop is that the last word is not + // loaded and thus parf of the last word written is not correct. + // To fix that, we simply copy the tail byte by byte. + + sub len1=endsrc,src1,1 + clrrrb + ;; + mov ar.ec=PIPE_DEPTH + mov pr.rot=1<<16 // p16=true all others are false + mov ar.lc=len1 + ;; +5: + EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) + + EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) + br.ctop.dptk.few 5b + ;; + mov pr=saved_pr,0xffffffffffff0000 + mov ar.pfs=saved_pfs + br.ret.dptk.few rp + + // // Beginning of long mempcy (i.e. > 16 bytes) // long_copy_user: @@ -142,7 +332,7 @@ ;; cmp.eq p10,p8=r0,tmp mov len1=len // copy because of rotation -(p8) br.cond.dpnt.few 1b // XXX Fixme. memcpy_diff_align +(p8) br.cond.dpnt.few diff_align_copy_user ;; // At this point we know we have more than 16 bytes to copy // and also that both src and dest have the same alignment @@ -267,6 +457,21 @@ mov ar.pfs=saved_pfs br.ret.dptk.few rp + // + // This is the case where the byte by byte copy fails on the load + // when we copy the head. We need to finish the pipeline and copy + // zeros for the rest of the destination. Since this happens + // at the top we still need to fill the body and tail. +failure_in_pipe2: + sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied +2: +(p16) mov val1[0]=r0 +(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1 + br.ctop.dptk.few 2b + ;; + sub len=enddst,dst1,1 // precompute len + br.cond.dptk.few failure_in1bis + ;; // // Here we handle the head & tail part when we check for alignment. @@ -395,6 +600,23 @@ mov ar.pfs=saved_pfs br.ret.dptk.few rp +failure_in2: + sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied + ;; +3: +(p16) mov val1[0]=r0 +(EPI) st8 [dst1]=val1[PIPE_DEPTH-1],8 + br.ctop.dptk.few 3b + ;; + cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ? + sub len=enddst,dst1,1 // precompute len +(p6) br.cond.dptk.few failure_in1bis + ;; + mov pr=saved_pr,0xffffffffffff0000 + mov ar.lc=saved_lc + mov ar.pfs=saved_pfs + br.ret.dptk.few rp + // // handling of failures on stores: that's the easy part // diff -urN linux-davidm/arch/ia64/lib/memcpy.S lia64/arch/ia64/lib/memcpy.S --- linux-davidm/arch/ia64/lib/memcpy.S Thu Aug 24 08:17:30 2000 +++ lia64/arch/ia64/lib/memcpy.S Mon Oct 30 22:45:50 2000 @@ -17,17 +17,24 @@ #include +#if defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC) +# define BRP(args...) nop.b 0 +#else +# define BRP(args...) brp.loop.imp args +#endif + GLOBAL_ENTRY(bcopy) .regstk 3,0,0,0 mov r8=in0 mov in0=in1 ;; mov in1=r8 + ;; END(bcopy) // FALL THROUGH GLOBAL_ENTRY(memcpy) -# define MEM_LAT 2 /* latency to L1 cache */ +# define MEM_LAT 21 /* latency to memory */ # define dst r2 # define src r3 @@ -57,20 +64,17 @@ UNW(.prologue) UNW(.save ar.pfs, saved_pfs) alloc saved_pfs=ar.pfs,3,Nrot,0,Nrot -#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) - lfetch [in1] -#else - nop.m 0 -#endif + UNW(.save ar.lc, saved_lc) + mov saved_lc=ar.lc or t0=in0,in1 ;; or t0=t0,in2 - UNW(.save ar.lc, saved_lc) - mov saved_lc=ar.lc UNW(.save pr, saved_pr) mov saved_pr=pr + UNW(.body) + cmp.eq p6,p0=in2,r0 // zero length? mov retval=in0 // return dst (p6) br.ret.spnt.many rp // zero length, return immediately @@ -83,7 +87,6 @@ adds cnt=-1,cnt // br.ctop is repeat/until cmp.gtu p7,p0,in2 // copying less than 16 bytes? - UNW(.body) mov ar.ec=N ;; @@ -98,10 +101,17 @@ ;; .rotr val[N] .rotp p[N] -1: + .align 32 +1: { .mib (p[0]) ld8 val[0]=[src],8 + nop.i 0 + BRP(1b, 2f) +} +2: { .mfb (p[N-1])st8 [dst]=val[N-1],8 + nop.f 0 br.ctop.dptk.few 1b +} ;; mov ar.lc=saved_lc mov pr=saved_pr,-1 @@ -118,6 +128,7 @@ memcpy_short: adds cnt=-1,in2 // br.ctop is repeat/until mov ar.ec=MEM_LAT + BRP(1f, 2f) ;; mov ar.lc=cnt ;; @@ -125,12 +136,17 @@ * It is faster to put a stop bit in the loop here because it makes * the pipeline shorter (and latency is what matters on short copies). */ -1: + .align 32 +1: { .mib (p[0]) ld1 val[0]=[src],1 - ;; + nop.i 0 + BRP(1b, 2f) +} ;; +2: { .mfb (p[MEM_LAT-1])st1 [dst]=val[MEM_LAT-1],1 + nop.f 0 br.ctop.dptk.few 1b - ;; +} ;; mov ar.lc=saved_lc mov pr=saved_pr,-1 mov ar.pfs=saved_pfs @@ -251,17 +267,16 @@ .align 64 #define COPY(shift,index) \ - 1: \ - { .mfi \ + 1: { .mib \ (p[0]) ld8 val[0]=[src2],8; \ - nop.f 0; \ (p[MEM_LAT+3]) shrp w[0]=val[MEM_LAT+3],val[MEM_LAT+4-index],shift; \ - }; \ - { .mbb \ + BRP(1b, 2f) \ + }; \ + 2: { .mfb \ (p[MEM_LAT+4]) st8 [dst]=w[1],8; \ - nop.b 0; \ + nop.f 0; \ br.ctop.dptk.few 1b; \ - }; \ + }; \ ;; \ ld8 val[N-1]=[src_end]; /* load last word (may be same as val[N]) */ \ ;; \ diff -urN linux-davidm/arch/ia64/mm/tlb.c lia64/arch/ia64/mm/tlb.c --- linux-davidm/arch/ia64/mm/tlb.c Thu Aug 24 08:17:30 2000 +++ lia64/arch/ia64/mm/tlb.c Mon Oct 30 22:46:48 2000 @@ -6,6 +6,8 @@ * * 08/02/00 A. Mallick * Modified RID allocation for SMP + * Goutham Rao + * IPI based ptc implementation and A-step IPI implementation. */ #include #include @@ -17,6 +19,7 @@ #include #include #include +#include #define SUPPORTED_PGBITS ( \ 1 << _PAGE_SIZE_256M | \ @@ -99,9 +102,22 @@ /* * Wait for other CPUs to finish purging entries. */ +#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) + { + unsigned long start = ia64_get_itc(); + while (atomic_read(&flush_cpu_count) > 0) { + if ((ia64_get_itc() - start) > 40000UL) { + atomic_set(&flush_cpu_count, smp_num_cpus - 1); + smp_send_flush_tlb(); + start = ia64_get_itc(); + } + } + } +#else while (atomic_read(&flush_cpu_count)) { /* Nothing */ } +#endif if (!(flags & IA64_PSR_I)) { local_irq_disable(); ia64_set_tpr(saved_tpr); diff -urN linux-davidm/drivers/char/drm/vm.c lia64/drivers/char/drm/vm.c --- linux-davidm/drivers/char/drm/vm.c Wed Oct 4 16:53:20 2000 +++ lia64/drivers/char/drm/vm.c Mon Oct 30 22:48:30 2000 @@ -272,6 +272,7 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_map_t *map = NULL; + unsigned long off; int i; DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", @@ -288,7 +289,16 @@ bit longer. */ for (i = 0; i < dev->map_count; i++) { map = dev->maplist[i]; - if (map->offset = VM_OFFSET(vma)) break; + off = map->offset ^ VM_OFFSET(vma); +#ifdef __ia64__ + /* + * Ignore region bits, makes IA32 processes happier + * XXX This is a hack... + */ + off &= ~0xe000000000000000; +#endif // __ia64__ + if (off = 0) + break; } if (i >= dev->map_count) return -EINVAL; diff -urN linux-davidm/drivers/char/mem.c lia64/drivers/char/mem.c --- linux-davidm/drivers/char/mem.c Wed Oct 4 16:53:21 2000 +++ lia64/drivers/char/mem.c Tue Oct 31 00:13:05 2000 @@ -198,8 +198,12 @@ * through a file pointer that was marked O_SYNC will be * done non-cached. */ - if (noncached_address(offset) || (file->f_flags & O_SYNC)) + if (noncached_address(offset) || (file->f_flags & O_SYNC) + || vma->vm_flags & VM_NONCACHED) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (vma->vm_flags & VM_WRITECOMBINED) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); /* * Don't dump addresses that are not real memory to a core file. diff -urN linux-davidm/drivers/net/tulip/tulip_core.c lia64/drivers/net/tulip/tulip_core.c --- linux-davidm/drivers/net/tulip/tulip_core.c Wed Oct 4 16:53:25 2000 +++ lia64/drivers/net/tulip/tulip_core.c Mon Oct 30 22:49:57 2000 @@ -52,7 +52,7 @@ /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ - || defined(__sparc_) + || defined(__sparc_) || defined(__ia64__) static int rx_copybreak = 1518; #else static int rx_copybreak = 100; @@ -71,7 +71,7 @@ ToDo: Non-Intel setting could be better. */ -#if defined(__alpha__) +#if defined(__alpha__) || defined(__ia64__) static int csr0 = 0x01A00000 | 0xE000; #elif defined(__i386__) || defined(__powerpc__) || defined(__hppa__) static int csr0 = 0x01A00000 | 0x8000; diff -urN linux-davidm/drivers/scsi/qla1280.c lia64/drivers/scsi/qla1280.c --- linux-davidm/drivers/scsi/qla1280.c Mon Oct 30 23:54:14 2000 +++ lia64/drivers/scsi/qla1280.c Mon Oct 30 22:50:11 2000 @@ -16,9 +16,17 @@ * General Public License for more details. ** ******************************************************************************/ - +#define QLA1280_VERSION "3.19 Beta" /**************************************************************************** Revision History: + Rev 3.19 Beta October 13, 2000 BN Qlogic + - Declare driver_template for new kernel + (2.4.0 and greater) scsi initialization scheme. + - Update /proc/scsi entry for 2.3.18 kernels and + above as qla1280 + Rev 3.18 Beta October 10, 2000 BN Qlogic + - Changed scan order of adapters to map + the QLA12160 followed by the QLA1280. Rev 3.17 Beta September 18, 2000 BN Qlogic - Removed warnings for 32 bit 2.4.x compiles - Corrected declared size for request and response @@ -102,8 +110,6 @@ #include #endif -#define QLA1280_VERSION "3.17 Beta" - #include #include #include @@ -408,14 +414,14 @@ struct _qlaboards QL1280BoardTbl[NUM_OF_ISP_DEVICES] = { /* Name , Board PCI Device ID, Number of ports */ + {"QLA12160 ", QLA12160_DEVICE_ID, 2, + &fw12160i_code01[0], (unsigned long *)&fw12160i_length01,&fw12160i_addr01, &fw12160i_version_str[0] }, {"QLA1080 ", QLA1080_DEVICE_ID, 1, &fw1280ei_code01[0], (unsigned long *)&fw1280ei_length01,&fw1280ei_addr01, &fw1280ei_version_str[0] }, {"QLA1240 ", QLA1240_DEVICE_ID, 2, &fw1280ei_code01[0], (unsigned long *)&fw1280ei_length01,&fw1280ei_addr01, &fw1280ei_version_str[0] }, {"QLA1280 ", QLA1280_DEVICE_ID, 2, &fw1280ei_code01[0], (unsigned long *)&fw1280ei_length01,&fw1280ei_addr01, &fw1280ei_version_str[0] }, - {"QLA12160 ", QLA12160_DEVICE_ID, 2, - &fw12160i_code01[0], (unsigned long *)&fw12160i_length01,&fw12160i_addr01, &fw12160i_version_str[0] }, {"QLA10160 ", QLA10160_DEVICE_ID, 1, &fw12160i_code01[0], (unsigned long *)&fw12160i_length01,&fw12160i_addr01, &fw12160i_version_str[0] }, {" ", 0, 0} @@ -739,7 +745,7 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) template->proc_dir = &proc_scsi_qla1280; #else - template->proc_name = "qla1x80"; + template->proc_name = "qla1280"; #endif /* Try and find each different type of adapter we support */ for( i=0; bdp->device_id != 0 && i < NUM_OF_ISP_DEVICES; i++, bdp++ ) { @@ -6342,13 +6348,15 @@ return(ret); } - -/* - * Declarations for load module - */ -static Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE; - +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +#ifdef MODULE +Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE; #include "scsi_module.c" +#endif +#else /* new kernel scsi initialization scheme */ +static Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE; +#include "scsi_module.c" +#endif /************************************************************************ * qla1280_check_for_dead_scsi_bus * diff -urN linux-davidm/fs/binfmt_elf.c lia64/fs/binfmt_elf.c --- linux-davidm/fs/binfmt_elf.c Mon Oct 30 23:54:14 2000 +++ lia64/fs/binfmt_elf.c Mon Oct 30 22:50:33 2000 @@ -33,6 +33,7 @@ #include #include +#include #include #define DLINFO_ITEMS 13 @@ -159,23 +160,27 @@ sp -= 2; NEW_AUX_ENT(0, AT_PLATFORM, (elf_addr_t)(unsigned long) u_platform); } - sp -= 2; + sp -= 2*2; NEW_AUX_ENT(0, AT_HWCAP, hwcap); + NEW_AUX_ENT(1, AT_PAGESZ, ELF_EXEC_PAGESIZE); +#ifdef CLOCKS_PER_SEC + sp -= 2; + NEW_AUX_ENT(0, AT_CLKTCK, CLOCKS_PER_SEC); +#endif if (exec) { - sp -= 11*2; + sp -= 10*2; NEW_AUX_ENT(0, AT_PHDR, load_addr + exec->e_phoff); NEW_AUX_ENT(1, AT_PHENT, sizeof (struct elf_phdr)); NEW_AUX_ENT(2, AT_PHNUM, exec->e_phnum); - NEW_AUX_ENT(3, AT_PAGESZ, ELF_EXEC_PAGESIZE); - NEW_AUX_ENT(4, AT_BASE, interp_load_addr); - NEW_AUX_ENT(5, AT_FLAGS, 0); - NEW_AUX_ENT(6, AT_ENTRY, load_bias + exec->e_entry); - NEW_AUX_ENT(7, AT_UID, (elf_addr_t) current->uid); - NEW_AUX_ENT(8, AT_EUID, (elf_addr_t) current->euid); - NEW_AUX_ENT(9, AT_GID, (elf_addr_t) current->gid); - NEW_AUX_ENT(10, AT_EGID, (elf_addr_t) current->egid); + NEW_AUX_ENT(3, AT_BASE, interp_load_addr); + NEW_AUX_ENT(4, AT_FLAGS, 0); + NEW_AUX_ENT(5, AT_ENTRY, load_bias + exec->e_entry); + NEW_AUX_ENT(6, AT_UID, (elf_addr_t) current->uid); + NEW_AUX_ENT(7, AT_EUID, (elf_addr_t) current->euid); + NEW_AUX_ENT(8, AT_GID, (elf_addr_t) current->gid); + NEW_AUX_ENT(9, AT_EGID, (elf_addr_t) current->egid); } #undef NEW_AUX_ENT diff -urN linux-davidm/fs/open.c lia64/fs/open.c --- linux-davidm/fs/open.c Wed Oct 4 16:53:39 2000 +++ lia64/fs/open.c Mon Oct 30 22:50:49 2000 @@ -103,7 +103,7 @@ inode = nd.dentry->d_inode; error = -EACCES; - if (S_ISDIR(inode->i_mode)) + if (!S_ISREG(inode->i_mode)) goto dput_and_out; error = permission(inode,MAY_WRITE); @@ -164,7 +164,7 @@ dentry = file->f_dentry; inode = dentry->d_inode; error = -EACCES; - if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) + if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) goto out_putf; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) diff -urN linux-davidm/fs/proc/array.c lia64/fs/proc/array.c --- linux-davidm/fs/proc/array.c Fri Sep 8 14:34:59 2000 +++ lia64/fs/proc/array.c Mon Oct 30 22:51:05 2000 @@ -575,7 +575,7 @@ goto getlen_out; /* Check whether the mmaps could change if we sleep */ - volatile_task = (task != current || atomic_read(&mm->mm_users) > 1); + volatile_task = (task != current || atomic_read(&mm->mm_users) > 2); /* decode f_pos */ lineno = *ppos >> MAPS_LINE_SHIFT; diff -urN linux-davidm/include/asm-ia64/delay.h lia64/include/asm-ia64/delay.h --- linux-davidm/include/asm-ia64/delay.h Mon Oct 30 23:54:14 2000 +++ lia64/include/asm-ia64/delay.h Mon Oct 30 22:51:21 2000 @@ -55,6 +55,10 @@ unsigned long result; __asm__ __volatile__("mov %0=ar.itc" : "=r"(result) :: "memory"); +#ifdef CONFIG_ITANIUM + while (__builtin_expect ((__s32) result = -1, 0)) + __asm__ __volatile__("mov %0=ar.itc" : "=r"(result) :: "memory"); +#endif return result; } diff -urN linux-davidm/include/asm-ia64/hw_irq.h lia64/include/asm-ia64/hw_irq.h --- linux-davidm/include/asm-ia64/hw_irq.h Mon Oct 30 23:54:14 2000 +++ lia64/include/asm-ia64/hw_irq.h Tue Oct 31 00:15:17 2000 @@ -31,13 +31,22 @@ #define IA64_SPURIOUS_INT 0x0f -#define IA64_MIN_VECTORED_IRQ 16 -#define IA64_MAX_VECTORED_IRQ 255 +/* + * Vectors 0x10-0x1f are used for low priority interrupts, e.g. CMCI. + */ +#define PCE_IRQ 0x1e /* platform corrected error interrupt vector */ +#define CMC_IRQ 0x1f /* correctable machine-check interrupt vector */ +/* + * Vectors 0x20-0x2f are reserved for legacy ISA IRQs. + */ +#define FIRST_DEVICE_IRQ 0x30 +#define LAST_DEVICE_IRQ 0xe7 -#define PERFMON_IRQ 0x28 /* performanc monitor interrupt vector */ +#define MCA_RENDEZ_IRQ 0xe8 /* MCA rendez interrupt */ +#define PERFMON_IRQ 0xee /* performanc monitor interrupt vector */ #define TIMER_IRQ 0xef /* use highest-prio group 15 interrupt for timer */ +#define MCA_WAKEUP_IRQ 0xf0 /* MCA wakeup interrupt (must be higher than MCA_RENDEZ_IRQ) */ #define IPI_IRQ 0xfe /* inter-processor interrupt vector */ -#define CMC_IRQ 0xff /* correctable machine-check interrupt vector */ /* IA64 inter-cpu interrupt related definitions */ @@ -62,12 +71,13 @@ extern struct hw_interrupt_type irq_type_ia64_sapic; /* CPU-internal interrupt controller */ -extern void ipi_send (int cpu, int vector, int delivery_mode, int redirect); +extern int ia64_alloc_irq (void); /* allocate a free irq */ +extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); static inline void hw_resend_irq (struct hw_interrupt_type *h, unsigned int vector) { - ipi_send(smp_processor_id(), vector, IA64_IPI_DM_INT, 0); + ia64_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0); } #endif /* _ASM_IA64_HW_IRQ_H */ diff -urN linux-davidm/include/asm-ia64/ia32.h lia64/include/asm-ia64/ia32.h --- linux-davidm/include/asm-ia64/ia32.h Mon Oct 30 23:54:14 2000 +++ lia64/include/asm-ia64/ia32.h Mon Oct 30 22:53:22 2000 @@ -5,6 +5,8 @@ #ifdef CONFIG_IA32_SUPPORT +#include + /* * 32 bit structures for IA32 support. */ @@ -32,6 +34,8 @@ #define IA32_PAGE_SHIFT 12 /* 4KB pages */ #define IA32_PAGE_SIZE (1ULL << IA32_PAGE_SHIFT) +#define IA32_CLOCKS_PER_SEC 100 /* Cast in stone for IA32 Linux */ +#define IA32_TICK(tick) ((unsigned long long)(tick) * IA32_CLOCKS_PER_SEC / CLOCKS_PER_SEC) /* fcntl.h */ struct flock32 { diff -urN linux-davidm/include/asm-ia64/iosapic.h lia64/include/asm-ia64/iosapic.h --- linux-davidm/include/asm-ia64/iosapic.h Thu Jun 22 07:09:45 2000 +++ lia64/include/asm-ia64/iosapic.h Mon Oct 30 22:53:32 2000 @@ -3,121 +3,60 @@ #include -#define IO_SAPIC_DEFAULT_ADDR 0xFEC00000 +#define IOSAPIC_DEFAULT_ADDR 0xFEC00000 -#define IO_SAPIC_REG_SELECT 0x0 -#define IO_SAPIC_WINDOW 0x10 -#define IO_SAPIC_EOI 0x40 +#define IOSAPIC_REG_SELECT 0x0 +#define IOSAPIC_WINDOW 0x10 +#define IOSAPIC_EOI 0x40 -#define IO_SAPIC_VERSION 0x1 +#define IOSAPIC_VERSION 0x1 /* * Redirection table entry */ +#define IOSAPIC_RTE_LOW(i) (0x10+i*2) +#define IOSAPIC_RTE_HIGH(i) (0x11+i*2) -#define IO_SAPIC_RTE_LOW(i) (0x10+i*2) -#define IO_SAPIC_RTE_HIGH(i) (0x11+i*2) - - -#define IO_SAPIC_DEST_SHIFT 16 +#define IOSAPIC_DEST_SHIFT 16 /* * Delivery mode */ - -#define IO_SAPIC_DELIVERY_SHIFT 8 -#define IO_SAPIC_FIXED 0x0 -#define IO_SAPIC_LOWEST_PRIORITY 0x1 -#define IO_SAPIC_PMI 0x2 -#define IO_SAPIC_NMI 0x4 -#define IO_SAPIC_INIT 0x5 -#define IO_SAPIC_EXTINT 0x7 +#define IOSAPIC_DELIVERY_SHIFT 8 +#define IOSAPIC_FIXED 0x0 +#define IOSAPIC_LOWEST_PRIORITY 0x1 +#define IOSAPIC_PMI 0x2 +#define IOSAPIC_NMI 0x4 +#define IOSAPIC_INIT 0x5 +#define IOSAPIC_EXTINT 0x7 /* * Interrupt polarity */ - -#define IO_SAPIC_POLARITY_SHIFT 13 -#define IO_SAPIC_POL_HIGH 0 -#define IO_SAPIC_POL_LOW 1 +#define IOSAPIC_POLARITY_SHIFT 13 +#define IOSAPIC_POL_HIGH 0 +#define IOSAPIC_POL_LOW 1 /* * Trigger mode */ - -#define IO_SAPIC_TRIGGER_SHIFT 15 -#define IO_SAPIC_EDGE 0 -#define IO_SAPIC_LEVEL 1 +#define IOSAPIC_TRIGGER_SHIFT 15 +#define IOSAPIC_EDGE 0 +#define IOSAPIC_LEVEL 1 /* * Mask bit */ - -#define IO_SAPIC_MASK_SHIFT 16 -#define IO_SAPIC_UNMASK 0 -#define IO_SAPIC_MSAK 1 - -/* - * Bus types - */ -#define BUS_ISA 0 /* ISA Bus */ -#define BUS_PCI 1 /* PCI Bus */ - -#ifndef CONFIG_IA64_PCI_FIRMWARE_IRQ -struct intr_routing_entry { - unsigned char srcbus; - unsigned char srcbusno; - unsigned char srcbusirq; - unsigned char iosapic_pin; - unsigned char dstiosapic; - unsigned char mode; - unsigned char trigger; - unsigned char polarity; -}; - -extern struct intr_routing_entry intr_routing[]; -#endif +#define IOSAPIC_MASK_SHIFT 16 +#define IOSAPIC_UNMASK 0 +#define IOSAPIC_MSAK 1 #ifndef __ASSEMBLY__ -#include - -/* - * IOSAPIC Version Register return 32 bit structure like: - * { - * unsigned int version : 8; - * unsigned int reserved1 : 8; - * unsigned int pins : 8; - * unsigned int reserved2 : 8; - * } - */ -extern unsigned int iosapic_version(unsigned long); -extern void iosapic_init(unsigned long, int); - -struct iosapic_vector { - unsigned long iosapic_base; /* IOSAPIC Base address */ - char pin; /* IOSAPIC pin (-1 = No data) */ - unsigned char bus; /* Bus number */ - unsigned char baseirq; /* Base IRQ handled by this IOSAPIC */ - unsigned char bustype; /* Bus type (ISA, PCI, etc) */ - unsigned int busdata; /* Bus specific ID */ - /* These bitfields use the values defined above */ - unsigned char dmode : 3; - unsigned char polarity : 1; - unsigned char trigger : 1; - unsigned char UNUSED : 3; -}; -extern struct iosapic_vector iosapic_vector[NR_IRQS]; - -#define iosapic_addr(v) iosapic_vector[v].iosapic_base -#define iosapic_pin(v) iosapic_vector[v].pin -#define iosapic_bus(v) iosapic_vector[v].bus -#define iosapic_baseirq(v) iosapic_vector[v].baseirq -#define iosapic_bustype(v) iosapic_vector[v].bustype -#define iosapic_busdata(v) iosapic_vector[v].busdata -#define iosapic_dmode(v) iosapic_vector[v].dmode -#define iosapic_trigger(v) iosapic_vector[v].trigger -#define iosapic_polarity(v) iosapic_vector[v].polarity +extern void __init iosapic_init (unsigned long address, unsigned int base_irq); +extern void iosapic_register_legacy_irq (unsigned long irq, unsigned long pin, + unsigned long polarity, unsigned long trigger); +extern void iosapic_pci_fixup (void); # endif /* !__ASSEMBLY__ */ #endif /* __ASM_IA64_IOSAPIC_H */ diff -urN linux-davidm/include/asm-ia64/machvec.h lia64/include/asm-ia64/machvec.h --- linux-davidm/include/asm-ia64/machvec.h Thu Aug 24 08:17:47 2000 +++ lia64/include/asm-ia64/machvec.h Mon Oct 30 23:37:09 2000 @@ -31,7 +31,6 @@ typedef void ia64_mv_mca_handler_t (void); typedef void ia64_mv_cmci_handler_t (int, void *, struct pt_regs *); typedef void ia64_mv_log_print_t (void); -typedef void ia64_mv_register_iosapic_t (struct acpi_entry_iosapic *); extern void machvec_noop (void); @@ -39,7 +38,7 @@ # include # elif defined (CONFIG_IA64_DIG) # include -# elif defined (CONFIG_IA64_SGI_SN1_SIM) +# elif defined (CONFIG_IA64_SGI_SN1) # include # elif defined (CONFIG_IA64_GENERIC) @@ -55,7 +54,6 @@ # define platform_cmci_handler ia64_mv.cmci_handler # define platform_log_print ia64_mv.log_print # define platform_pci_fixup ia64_mv.pci_fixup -# define platform_register_iosapic ia64_mv.register_iosapic # endif struct ia64_machine_vector { @@ -68,7 +66,6 @@ ia64_mv_mca_handler_t *mca_handler; ia64_mv_cmci_handler_t *cmci_handler; ia64_mv_log_print_t *log_print; - ia64_mv_register_iosapic_t *register_iosapic; }; #define MACHVEC_INIT(name) \ @@ -81,8 +78,7 @@ platform_mca_init, \ platform_mca_handler, \ platform_cmci_handler, \ - platform_log_print, \ - platform_register_iosapic \ + platform_log_print \ } extern struct ia64_machine_vector ia64_mv; @@ -116,9 +112,6 @@ #endif #ifndef platform_pci_fixup # define platform_pci_fixup ((ia64_mv_pci_fixup_t *) machvec_noop) -#endif -#ifndef platform_register_iosapic -# define platform_register_iosapic ((ia64_mv_register_iosapic_t *) machvec_noop) #endif #endif /* _ASM_IA64_MACHVEC_H */ diff -urN linux-davidm/include/asm-ia64/machvec_dig.h lia64/include/asm-ia64/machvec_dig.h --- linux-davidm/include/asm-ia64/machvec_dig.h Thu Aug 24 08:17:47 2000 +++ lia64/include/asm-ia64/machvec_dig.h Mon Oct 30 22:54:21 2000 @@ -5,7 +5,6 @@ extern ia64_mv_irq_init_t dig_irq_init; extern ia64_mv_pci_fixup_t dig_pci_fixup; extern ia64_mv_map_nr_t map_nr_dense; -extern ia64_mv_register_iosapic_t dig_register_iosapic; /* * This stuff has dual use! @@ -17,8 +16,7 @@ #define platform_name "dig" #define platform_setup dig_setup #define platform_irq_init dig_irq_init -#define platform_pci_fixup dig_pci_fixup +#define platform_pci_fixup iosapic_pci_fixup #define platform_map_nr map_nr_dense -#define platform_register_iosapic dig_register_iosapic #endif /* _ASM_IA64_MACHVEC_DIG_h */ diff -urN linux-davidm/include/asm-ia64/mca.h lia64/include/asm-ia64/mca.h --- linux-davidm/include/asm-ia64/mca.h Fri Apr 21 15:21:24 2000 +++ lia64/include/asm-ia64/mca.h Mon Oct 30 22:54:41 2000 @@ -18,6 +18,7 @@ #include #include #include +#include /* These are the return codes from all the IA64_MCA specific interfaces */ typedef int ia64_mca_return_code_t; @@ -30,9 +31,9 @@ #define IA64_MCA_RENDEZ_TIMEOUT (100 * HZ) /* 1000 milliseconds */ /* Interrupt vectors reserved for MC handling. */ -#define IA64_MCA_RENDEZ_INT_VECTOR 0xF3 /* Rendez interrupt */ -#define IA64_MCA_WAKEUP_INT_VECTOR 0x12 /* Wakeup interrupt */ -#define IA64_MCA_CMC_INT_VECTOR 0xF2 /* Correctable machine check interrupt */ +#define IA64_MCA_RENDEZ_INT_VECTOR MCA_RENDEZ_IRQ /* Rendez interrupt */ +#define IA64_MCA_WAKEUP_INT_VECTOR MCA_WAKEUP_IRQ /* Wakeup interrupt */ +#define IA64_MCA_CMC_INT_VECTOR CMC_IRQ /* Correctable machine check interrupt */ #define IA64_CMC_INT_DISABLE 0 #define IA64_CMC_INT_ENABLE 1 diff -urN linux-davidm/include/asm-ia64/mman.h lia64/include/asm-ia64/mman.h --- linux-davidm/include/asm-ia64/mman.h Fri Apr 21 15:21:24 2000 +++ lia64/include/asm-ia64/mman.h Mon Oct 30 22:54:48 2000 @@ -23,6 +23,8 @@ #define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define MAP_LOCKED 0x2000 /* pages are locked */ #define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_WRITECOMBINED 0x10000 /* write-combine the area */ +#define MAP_NONCACHED 0x20000 /* don't cache the memory */ #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_INVALIDATE 2 /* invalidate the caches */ diff -urN linux-davidm/include/asm-ia64/param.h lia64/include/asm-ia64/param.h --- linux-davidm/include/asm-ia64/param.h Mon Oct 30 23:54:14 2000 +++ lia64/include/asm-ia64/param.h Mon Oct 30 22:55:07 2000 @@ -32,4 +32,8 @@ #define MAXHOSTNAMELEN 64 /* max length of hostname */ +#ifdef __KERNEL__ +# define CLOCKS_PER_SEC HZ /* frequency at which times() counts */ +#endif + #endif /* _ASM_IA64_PARAM_H */ diff -urN linux-davidm/include/asm-ia64/processor.h lia64/include/asm-ia64/processor.h --- linux-davidm/include/asm-ia64/processor.h Mon Oct 30 23:54:14 2000 +++ lia64/include/asm-ia64/processor.h Mon Oct 30 22:56:56 2000 @@ -4,7 +4,7 @@ /* * Copyright (C) 1998-2000 Hewlett-Packard Co * Copyright (C) 1998-2000 David Mosberger-Tang - * Copyright (C) 1998, 1999 Stephane Eranian + * Copyright (C) 1998-2000 Stephane Eranian * Copyright (C) 1999 Asit Mallick * Copyright (C) 1999 Don Dugger * @@ -19,7 +19,13 @@ #include #define IA64_NUM_DBG_REGS 8 -#define IA64_NUM_PM_REGS 4 +/* + * Limits for PMC and PMD are set to less than maximum architected values + * but should be sufficient for a while + */ +#define IA64_NUM_PMC_REGS 32 +#define IA64_NUM_PMD_REGS 32 +#define IA64_NUM_PMD_COUNTERS 4 /* * TASK_SIZE really is a mis-named. It really is the maximum user @@ -288,10 +294,15 @@ __u64 dbr[IA64_NUM_DBG_REGS]; __u64 ibr[IA64_NUM_DBG_REGS]; #ifdef CONFIG_PERFMON - __u64 pmc[IA64_NUM_PM_REGS]; - __u64 pmd[IA64_NUM_PM_REGS]; - __u64 pmod[IA64_NUM_PM_REGS]; -# define INIT_THREAD_PM {0, }, {0, }, {0, }, + __u64 pmc[IA64_NUM_PMC_REGS]; + __u64 pmd[IA64_NUM_PMD_REGS]; + struct { + __u64 val; /* virtual 64bit counter */ + __u64 rval; /* reset value on overflow */ + int sig; /* signal used to notify */ + int pid; /* process to notify */ + } pmu_counters[IA64_NUM_PMD_COUNTERS]; +# define INIT_THREAD_PM {0, }, {0, }, {{ 0, 0, 0, 0}, }, #else # define INIT_THREAD_PM #endif @@ -423,8 +434,8 @@ #endif #ifdef CONFIG_PERFMON -extern void ia64_save_pm_regs (struct thread_struct *thread); -extern void ia64_load_pm_regs (struct thread_struct *thread); +extern void ia64_save_pm_regs (struct task_struct *task); +extern void ia64_load_pm_regs (struct task_struct *task); #endif #define ia64_fph_enable() __asm__ __volatile__ (";; rsm psr.dfh;; srlz.d;;" ::: "memory"); diff -urN linux-davidm/include/asm-ia64/spinlock.h lia64/include/asm-ia64/spinlock.h --- linux-davidm/include/asm-ia64/spinlock.h Mon Oct 30 23:54:14 2000 +++ lia64/include/asm-ia64/spinlock.h Mon Oct 30 22:57:29 2000 @@ -18,8 +18,9 @@ #undef NEW_LOCK #ifdef NEW_LOCK + typedef struct { - volatile unsigned char lock; + volatile unsigned int lock; } spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } @@ -38,7 +39,7 @@ "mov r30=1\n" \ "mov ar.ccv=r0\n" \ ";;\n" \ - IA64_SEMFIX"cmpxchg1.acq r30=[%0],r30,ar.ccv\n" \ + IA64_SEMFIX"cmpxchg4.acq r30=[%0],r30,ar.ccv\n" \ ";;\n" \ "cmp.ne p15,p0=r30,r0\n" \ "(p15) br.call.spnt.few b7=ia64_spinlock_contention\n" \ @@ -48,18 +49,16 @@ : "ar.ccv", "ar.pfs", "b7", "p15", "r28", "r29", "r30", "memory"); \ } -#define spin_trylock(x) \ -({ \ - register char *addr __asm__ ("r31") = (char *) &(x)->lock; \ - register long result; \ - \ - __asm__ __volatile__ ( \ - "mov r30=1\n" \ - "mov ar.ccv=r0\n" \ - ";;\n" \ - IA64_SEMFIX"cmpxchg1.acq %0=[%1],r30,ar.ccv\n" \ - : "=r"(result) : "r"(addr) : "ar.ccv", "r30", "memory"); \ - (result = 0); \ +#define spin_trylock(x) \ +({ \ + register long result; \ + \ + __asm__ __volatile__ ( \ + "mov ar.ccv=r0\n" \ + ";;\n" \ + IA64_SEMFIX"cmpxchg4.acq %0=[%2],%1,ar.ccv\n" \ + : "=r"(result) : "r"(1), "r"(&(x)->lock) : "ar.ccv", "memory"); \ + (result = 0); \ }) #define spin_is_locked(x) ((x)->lock != 0) diff -urN linux-davidm/include/asm-ia64/system.h lia64/include/asm-ia64/system.h --- linux-davidm/include/asm-ia64/system.h Mon Oct 30 23:54:14 2000 +++ lia64/include/asm-ia64/system.h Mon Oct 30 22:57:47 2000 @@ -27,7 +27,8 @@ #define GATE_ADDR (0xa000000000000000 + PAGE_SIZE) -#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) +#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC) /* Workaround for Errata 97. */ # define IA64_SEMFIX_INSN mf; # define IA64_SEMFIX "mf;" diff -urN linux-davidm/include/asm-ia64/uaccess.h lia64/include/asm-ia64/uaccess.h --- linux-davidm/include/asm-ia64/uaccess.h Mon Oct 30 23:54:14 2000 +++ lia64/include/asm-ia64/uaccess.h Mon Oct 30 22:58:00 2000 @@ -125,46 +125,28 @@ struct __large_struct { unsigned long buf[100]; }; #define __m(x) (*(struct __large_struct *)(x)) -#define __get_user_64(addr) \ +/* We need to declare the __ex_table section before we can use it in .xdata. */ +__asm__ (".section \"__ex_table\", \"a\"\n\t.previous"); + +#define __get_user_64(addr) \ __asm__ ("\n1:\tld8 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "2:\n" \ - "\t.section __ex_table,\"a\"\n" \ - "\t\tdata4 @gprel(1b)\n" \ - "\t\tdata4 (2b-1b)|1\n" \ - "\t.previous" \ - : "=r"(__gu_val), "=r"(__gu_err) \ - : "m"(__m(addr)), "1"(__gu_err)); + "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n" \ + : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); -#define __get_user_32(addr) \ +#define __get_user_32(addr) \ __asm__ ("\n1:\tld4 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "2:\n" \ - "\t.section __ex_table,\"a\"\n" \ - "\t\tdata4 @gprel(1b)\n" \ - "\t\tdata4 (2b-1b)|1\n" \ - "\t.previous" \ - : "=r"(__gu_val), "=r"(__gu_err) \ - : "m"(__m(addr)), "1"(__gu_err)); + "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n" \ + : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); -#define __get_user_16(addr) \ +#define __get_user_16(addr) \ __asm__ ("\n1:\tld2 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "2:\n" \ - "\t.section __ex_table,\"a\"\n" \ - "\t\tdata4 @gprel(1b)\n" \ - "\t\tdata4 (2b-1b)|1\n" \ - "\t.previous" \ - : "=r"(__gu_val), "=r"(__gu_err) \ - : "m"(__m(addr)), "1"(__gu_err)); + "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n" \ + : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); -#define __get_user_8(addr) \ +#define __get_user_8(addr) \ __asm__ ("\n1:\tld1 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "2:\n" \ - "\t.section __ex_table,\"a\"\n" \ - "\t\tdata4 @gprel(1b)\n" \ - "\t\tdata4 (2b-1b)|1\n" \ - "\t.previous" \ - : "=r"(__gu_val), "=r"(__gu_err) \ - : "m"(__m(addr)), "1"(__gu_err)); - + "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n" \ + : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); extern void __put_user_unknown (void); @@ -206,46 +188,26 @@ #define __put_user_64(x,addr) \ __asm__ __volatile__ ( \ "\n1:\tst8 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "2:\n" \ - "\t.section __ex_table,\"a\"\n" \ - "\t\tdata4 @gprel(1b)\n" \ - "\t\tdata4 2b-1b\n" \ - "\t.previous" \ - : "=r"(__pu_err) \ - : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) + "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n" \ + : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) #define __put_user_32(x,addr) \ __asm__ __volatile__ ( \ "\n1:\tst4 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "2:\n" \ - "\t.section __ex_table,\"a\"\n" \ - "\t\tdata4 @gprel(1b)\n" \ - "\t\tdata4 2b-1b\n" \ - "\t.previous" \ - : "=r"(__pu_err) \ - : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) + "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n" \ + : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) #define __put_user_16(x,addr) \ __asm__ __volatile__ ( \ "\n1:\tst2 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "2:\n" \ - "\t.section __ex_table,\"a\"\n" \ - "\t\tdata4 @gprel(1b)\n" \ - "\t\tdata4 2b-1b\n" \ - "\t.previous" \ - : "=r"(__pu_err) \ - : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) + "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n" \ + : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) #define __put_user_8(x,addr) \ __asm__ __volatile__ ( \ "\n1:\tst1 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "2:\n" \ - "\t.section __ex_table,\"a\"\n" \ - "\t\tdata4 @gprel(1b)\n" \ - "\t\tdata4 2b-1b\n" \ - "\t.previous" \ - : "=r"(__pu_err) \ - : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) + "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n" \ + : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) /* * Complex access routines diff -urN linux-davidm/include/asm-ia64/unistd.h lia64/include/asm-ia64/unistd.h --- linux-davidm/include/asm-ia64/unistd.h Mon Oct 30 23:54:14 2000 +++ lia64/include/asm-ia64/unistd.h Tue Oct 31 00:18:03 2000 @@ -160,7 +160,7 @@ #define __NR_nanosleep 1168 #define __NR_nfsservctl 1169 #define __NR_prctl 1170 -#define __NR_getpagesize 1171 +/* 1171 is reserved for backwards compatibility with old __NR_getpagesize */ #define __NR_mmap2 1172 #define __NR_pciconfig_read 1173 #define __NR_pciconfig_write 1174 diff -urN linux-davidm/include/linux/elf.h lia64/include/linux/elf.h --- linux-davidm/include/linux/elf.h Wed Oct 4 16:53:43 2000 +++ lia64/include/linux/elf.h Mon Oct 30 22:58:27 2000 @@ -165,6 +165,7 @@ #define AT_EGID 14 /* effective gid */ #define AT_PLATFORM 15 /* string identifying CPU for optimizations */ #define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */ +#define AT_CLKTCK 17 /* frequency at which times() increments */ typedef struct dynamic{ Elf32_Sword d_tag; diff -urN linux-davidm/include/linux/mm.h lia64/include/linux/mm.h --- linux-davidm/include/linux/mm.h Wed Oct 4 16:53:43 2000 +++ lia64/include/linux/mm.h Mon Oct 30 22:58:40 2000 @@ -95,6 +95,8 @@ #define VM_DONTCOPY 0x00020000 /* Do not copy this vma on fork */ #define VM_DONTEXPAND 0x00040000 /* Cannot expand with mremap() */ +#define VM_WRITECOMBINED 0x00100000 /* Write-combined */ +#define VM_NONCACHED 0x00200000 /* Noncached access */ #define VM_STACK_FLAGS 0x00000177 diff -urN linux-davidm/mm/mmap.c lia64/mm/mmap.c --- linux-davidm/mm/mmap.c Fri Sep 8 14:35:08 2000 +++ lia64/mm/mmap.c Mon Oct 30 23:02:32 2000 @@ -151,6 +151,12 @@ _trans(prot, PROT_WRITE, VM_WRITE) | _trans(prot, PROT_EXEC, VM_EXEC); flag_bits +#ifdef MAP_WRITECOMBINED + _trans(flags, MAP_WRITECOMBINED, VM_WRITECOMBINED) | +#endif +#ifdef MAP_NONCACHED + _trans(flags, MAP_NONCACHED, VM_NONCACHED) | +#endif _trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN) | _trans(flags, MAP_DENYWRITE, VM_DENYWRITE) | _trans(flags, MAP_EXECUTABLE, VM_EXECUTABLE);