diff options
Diffstat (limited to 'arch/ia64/sn/kernel')
27 files changed, 1039 insertions, 4189 deletions
diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile index 35191abfd28c9..12e488eb044cf 100644 --- a/arch/ia64/sn/kernel/Makefile +++ b/arch/ia64/sn/kernel/Makefile @@ -9,11 +9,8 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -obj-y := probe.o setup.o sn_asm.o sv.o bte.o iomv.o \ - irq.o mca.o +obj-y := probe.o setup.o sv.o bte.o irq.o mca.o obj-$(CONFIG_IA64_SGI_SN2) += sn2/ -obj-$(CONFIG_IA64_SGI_AUTOTEST) += llsc4.o misctest.o obj-$(CONFIG_IA64_GENERIC) += machvec.o obj-$(CONFIG_MODULES) += sn_ksyms.o -obj-$(CONFIG_IA64_SGI_SN_BRT) += bte_regr_test.o diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c index 0e592be762ea7..88409fcc4b8cd 100644 --- a/arch/ia64/sn/kernel/bte.c +++ b/arch/ia64/sn/kernel/bte.c @@ -1,7 +1,7 @@ /* * * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -38,124 +38,160 @@ #include <asm/sn/arch.h> #include <asm/sn/sn_cpuid.h> #include <asm/sn/pda.h> -#ifdef CONFIG_IA64_SGI_SN2 #include <asm/sn/sn2/shubio.h> -#endif #include <asm/nodedata.h> #include <linux/bootmem.h> #include <linux/string.h> #include <linux/sched.h> -#include <asm/sn/bte_copy.h> +#include <asm/sn/bte.h> -int bte_offsets[] = { IIO_IBLS0, IIO_IBLS1 }; +#ifndef L1_CACHE_MASK +#define L1_CACHE_MASK (L1_CACHE_BYTES - 1) +#endif /* - * bte_init_node(nodepda, cnode) + * The base address of for each set of bte registers. + */ +static int bte_offsets[] = { IIO_IBLS0, IIO_IBLS1 }; + + +/************************************************************************ + * Block Transfer Engine copy related functions. * - * Initialize the nodepda structure with BTE base addresses and - * spinlocks. + ***********************************************************************/ + + +/* + * bte_copy(src, dest, len, mode, notification) + * + * Use the block transfer engine to move kernel memory from src to dest + * using the assigned mode. + * + * Paramaters: + * src - physical address of the transfer source. + * dest - physical address of the transfer destination. + * len - number of bytes to transfer from source to dest. + * mode - hardware defined. See reference information + * for IBCT0/1 in the SHUB Programmers Reference + * notification - kernel virtual address of the notification cache + * line. If NULL, the default is used and + * the bte_copy is synchronous. * - * NOTE: The kernel parameter btetest will cause the initialization - * code to reserve blocks of physically contiguous memory to be - * used by the bte test module. + * NOTE: This function requires src, dest, and len to + * be cacheline aligned. */ -void -bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode) +bte_result_t +bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) { - int i; + int bte_to_use; + u64 transfer_size; + struct bteinfo_s *bte; + bte_result_t bte_status; + unsigned long irq_flags; - /* - * Indicate that all the block transfer engines on this node - * are available. - */ - for (i = 0; i < BTES_PER_NODE; i++) { -#ifdef CONFIG_IA64_SGI_SN2 - /* >>> Don't know why the 0x1800000L is here. Robin */ - mynodepda->bte_if[i].bte_base_addr = - (char *)LOCAL_MMR_ADDR(bte_offsets[i] | 0x1800000L); + BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n", + src, dest, len, mode, notification)); -#elif CONFIG_IA64_SGI_SN1 - mynodepda->bte_if[i].bte_base_addr = - (char *)LOCAL_HUB_ADDR(bte_offsets[i]); -#else -#error BTE Not defined for this hardware platform. -#endif + if (len == 0) { + return BTE_SUCCESS; + } + + ASSERT(!((len & L1_CACHE_MASK) || + (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK))); + ASSERT(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)); + + do { + local_irq_save(irq_flags); + + bte_to_use = 0; + /* Attempt to lock one of the BTE interfaces. */ + while ((bte_to_use < BTES_PER_NODE) && + BTE_LOCK_IF_AVAIL(bte_to_use)) { + bte_to_use++; + } + + if (bte_to_use < BTES_PER_NODE) { + break; + } + + local_irq_restore(irq_flags); + + if (!(mode & BTE_WACQUIRE)) { + return BTEFAIL_NOTAVAIL; + } + + /* Wait until a bte is available. */ + udelay(10); + } while (1); + + bte = pda->cpu_bte_if[bte_to_use]; + BTE_PRINTKV(("Got a lock on bte %d\n", bte_to_use)); - /* - * Initialize the notification and spinlock - * so the first transfer can occur. - */ - mynodepda->bte_if[i].most_rcnt_na = - &(mynodepda->bte_if[i].notify); - mynodepda->bte_if[i].notify = 0L; -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - spin_lock_init(&mynodepda->bte_if[i].spinlock); -#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ - mynodepda->bte_if[i].bte_test_buf = - alloc_bootmem_node(NODE_DATA(cnode), BTE_MAX_XFER); + if (notification == NULL) { + /* User does not want to be notified. */ + bte->most_rcnt_na = &bte->notify; + } else { + bte->most_rcnt_na = notification; } -} + /* Calculate the number of cache lines to transfer. */ + transfer_size = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK); + /* Initialize the notification to a known value. */ + *bte->most_rcnt_na = -1L; -/* - * bte_reset_nasid(nasid_t) - * - * Does a soft reset of the BTEs on the specified nasid. - * This is followed by a one-line transfer from each of the - * virtual interfaces. - */ -void -bte_reset_nasid(nasid_t n) -{ - ii_ibcr_u_t ibcr; - - ibcr.ii_ibcr_regval = REMOTE_HUB_L(n, IIO_IBCR); - ibcr.ii_ibcr_fld_s.i_soft_reset = 1; - REMOTE_HUB_S(n, IIO_IBCR, ibcr.ii_ibcr_regval); - - /* One line transfer on virtual interface 0 */ - REMOTE_HUB_S(n, IIO_IBLS_0, IBLS_BUSY | 1); - REMOTE_HUB_S(n, IIO_IBSA_0, TO_PHYS(__pa(&nodepda->bte_cleanup))); - REMOTE_HUB_S(n, IIO_IBDA_0, - TO_PHYS(__pa(&nodepda->bte_cleanup[4*L1_CACHE_BYTES]))); - REMOTE_HUB_S(n, IIO_IBNA_0, - TO_PHYS(__pa(&nodepda->bte_cleanup[4*L1_CACHE_BYTES]))); - REMOTE_HUB_S(n, IIO_IBCT_0, BTE_NOTIFY); - while (REMOTE_HUB_L(n, IIO_IBLS0)) { - /* >>> Need some way out in case of hang... */ + /* Set the status reg busy bit and transfer length */ + BTE_PRINTKV(("IBLS - HUB_S(0x%p, 0x%lx)\n", + BTEREG_LNSTAT_ADDR, IBLS_BUSY | transfer_size)); + HUB_S(BTEREG_LNSTAT_ADDR, (IBLS_BUSY | transfer_size)); + + /* Set the source and destination registers */ + BTE_PRINTKV(("IBSA - HUB_S(0x%p, 0x%lx)\n", BTEREG_SRC_ADDR, + (TO_PHYS(src)))); + HUB_S(BTEREG_SRC_ADDR, (TO_PHYS(src))); + BTE_PRINTKV(("IBDA - HUB_S(0x%p, 0x%lx)\n", BTEREG_DEST_ADDR, + (TO_PHYS(dest)))); + HUB_S(BTEREG_DEST_ADDR, (TO_PHYS(dest))); + + /* Set the notification register */ + BTE_PRINTKV(("IBNA - HUB_S(0x%p, 0x%lx)\n", BTEREG_NOTIF_ADDR, + (TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na))))); + HUB_S(BTEREG_NOTIF_ADDR, (TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na)))); + + + /* Initiate the transfer */ + BTE_PRINTK(("IBCT - HUB_S(0x%p, 0x%lx)\n", BTEREG_CTRL_ADDR, + BTE_VALID_MODE(mode))); + HUB_S(BTEREG_CTRL_ADDR, BTE_VALID_MODE(mode)); + + spin_unlock_irqrestore(&bte->spinlock, irq_flags); + + + if (notification != NULL) { + return BTE_SUCCESS; } - /* One line transfer on virtual interface 1 */ - REMOTE_HUB_S(n, IIO_IBLS_1, IBLS_BUSY | 1); - REMOTE_HUB_S(n, IIO_IBSA_1, TO_PHYS(__pa(nodepda->bte_cleanup))); - REMOTE_HUB_S(n, IIO_IBDA_1, - TO_PHYS(__pa(nodepda->bte_cleanup[4 * L1_CACHE_BYTES]))); - REMOTE_HUB_S(n, IIO_IBNA_1, - TO_PHYS(__pa(nodepda->bte_cleanup[5 * L1_CACHE_BYTES]))); - REMOTE_HUB_S(n, IIO_IBCT_1, BTE_NOTIFY); - while (REMOTE_HUB_L(n, IIO_IBLS1)) { - /* >>> Need some way out in case of hang... */ + while (*bte->most_rcnt_na == -1UL) { } -} -/* - * bte_init_cpu() - * - * Initialize the cpupda structure with pointers to the - * nodepda bte blocks. - * - */ -void -bte_init_cpu(void) -{ - pda->cpu_bte_if[0] = &(nodepda->bte_if[1]); - pda->cpu_bte_if[1] = &(nodepda->bte_if[0]); + BTE_PRINTKV((" Delay Done. IBLS = 0x%lx, most_rcnt_na = 0x%lx\n", + HUB_L(BTEREG_LNSTAT_ADDR), *bte->most_rcnt_na)); + + if (*bte->most_rcnt_na & IBLS_ERROR) { + bte_status = *bte->most_rcnt_na & ~IBLS_ERROR; + *bte->most_rcnt_na = 0L; + } else { + bte_status = BTE_SUCCESS; + } + BTE_PRINTK(("Returning status is 0x%lx and most_rcnt_na is 0x%lx\n", + HUB_L(BTEREG_LNSTAT_ADDR), *bte->most_rcnt_na)); + + return bte_status; } @@ -192,15 +228,11 @@ bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode) char *bteBlock; if (len == 0) { - return (BTE_SUCCESS); + return BTE_SUCCESS; } -#ifdef CONFIG_IA64_SGI_BTE_LOCKING -#error bte_unaligned_copy() assumes single BTE selection in bte_copy(). -#else /* temporary buffer used during unaligned transfers */ - bteBlock = pda->cpu_bte_if[0]->bte_test_buf; -#endif + bteBlock = pda->cpu_bte_if[0]->scratch_buf; headBcopySrcOffset = src & L1_CACHE_MASK; destFirstCacheOffset = dest & L1_CACHE_MASK; @@ -265,15 +297,15 @@ bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode) headBteLen += footBteLen; } else if (footBcopyLen > 0) { rv = bte_copy(footBteSource, - __pa(bteBlock), + ia64_tpa((unsigned long)bteBlock), footBteLen, mode, NULL); if (rv != BTE_SUCCESS) { - return (rv); + return rv; } memcpy(__va(footBcopyDest), - (char *)bteBlock, footBcopyLen); + (char *) bteBlock, footBcopyLen); } } else { footBcopyLen = 0; @@ -288,7 +320,7 @@ bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode) (len - headBcopyLen - footBcopyLen), mode, NULL); if (rv != BTE_SUCCESS) { - return (rv); + return rv; } } @@ -315,14 +347,93 @@ bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode) if (headBcopyLen > 0) { rv = bte_copy(headBteSource, - __pa(bteBlock), headBteLen, mode, NULL); + ia64_tpa((unsigned long)bteBlock), headBteLen, mode, NULL); if (rv != BTE_SUCCESS) { - return (rv); + return rv; } - memcpy(__va(headBcopyDest), ((char *)bteBlock + + memcpy(__va(headBcopyDest), ((char *) bteBlock + headBcopySrcOffset), headBcopyLen); } - return (BTE_SUCCESS); + return BTE_SUCCESS; +} + + +/************************************************************************ + * Block Transfer Engine initialization functions. + * + ***********************************************************************/ + + +/* + * bte_init_node(nodepda, cnode) + * + * Initialize the nodepda structure with BTE base addresses and + * spinlocks. + */ +void +bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode) +{ + int i; + + + /* + * Indicate that all the block transfer engines on this node + * are available. + */ + + /* + * Allocate one bte_recover_t structure per node. It holds + * the recovery lock for node. All the bte interface structures + * will point at this one bte_recover structure to get the lock. + */ + spin_lock_init(&mynodepda->bte_recovery_lock); + init_timer(&mynodepda->bte_recovery_timer); + mynodepda->bte_recovery_timer.function = bte_error_handler; + mynodepda->bte_recovery_timer.data = (unsigned long) mynodepda; + + for (i = 0; i < BTES_PER_NODE; i++) { + /* >>> Don't know why the 0x1800000L is here. Robin */ + mynodepda->bte_if[i].bte_base_addr = + (char *) LOCAL_MMR_ADDR(bte_offsets[i] | 0x1800000L); + + /* + * Initialize the notification and spinlock + * so the first transfer can occur. + */ + mynodepda->bte_if[i].most_rcnt_na = + &(mynodepda->bte_if[i].notify); + mynodepda->bte_if[i].notify = 0L; + spin_lock_init(&mynodepda->bte_if[i].spinlock); + + mynodepda->bte_if[i].scratch_buf = + alloc_bootmem_node(NODE_DATA(cnode), BTE_MAX_XFER); + mynodepda->bte_if[i].bte_cnode = cnode; + mynodepda->bte_if[i].bte_error_count = 0; + mynodepda->bte_if[i].bte_num = i; + mynodepda->bte_if[i].cleanup_active = 0; + mynodepda->bte_if[i].bh_error = 0; + } + +} + +/* + * bte_init_cpu() + * + * Initialize the cpupda structure with pointers to the + * nodepda bte blocks. + * + */ +void +bte_init_cpu(void) +{ + /* Called by setup.c as each cpu is being added to the nodepda */ + if (local_node_data->active_cpu_count & 0x1) { + pda->cpu_bte_if[0] = &(nodepda->bte_if[0]); + pda->cpu_bte_if[1] = &(nodepda->bte_if[1]); + } else { + pda->cpu_bte_if[0] = &(nodepda->bte_if[1]); + pda->cpu_bte_if[1] = &(nodepda->bte_if[0]); + } } diff --git a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c deleted file mode 100644 index 6d439ee7521eb..0000000000000 --- a/arch/ia64/sn/kernel/iomv.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include <asm/io.h> -#include <linux/module.h> - -extern void * sn_io_addr(unsigned long port); /* defined in sn[12]/iomv.c */ - -/** - * sn_inb - read a byte from a port - * @port: port to read from - * - * Reads a byte from @port and returns it to the caller. - */ -unsigned int -sn_inb (unsigned long port) -{ - volatile unsigned char *addr = sn_io_addr(port); - unsigned char ret; - - ret = *addr; - __ia64_mf_a(); - return ret; -} - -/** - * sn_inw - read a word from a port - * @port: port to read from - * - * Reads a word from @port and returns it to the caller. - */ -unsigned int -sn_inw (unsigned long port) -{ - volatile unsigned short *addr = sn_io_addr(port); - unsigned short ret; - - ret = *addr; - __ia64_mf_a(); - return ret; -} - -/** - * sn_inl - read a word from a port - * @port: port to read from - * - * Reads a word from @port and returns it to the caller. - */ -unsigned int -sn_inl (unsigned long port) -{ - volatile unsigned int *addr = sn_io_addr(port); - unsigned int ret; - - ret = *addr; - __ia64_mf_a(); - return ret; -} - -/** - * sn_outb - write a byte to a port - * @port: port to write to - * @val: value to write - * - * Writes @val to @port. - */ -void -sn_outb (unsigned char val, unsigned long port) -{ - volatile unsigned char *addr = sn_io_addr(port); - - *addr = val; -} - -/** - * sn_outw - write a word to a port - * @port: port to write to - * @val: value to write - * - * Writes @val to @port. - */ -void -sn_outw (unsigned short val, unsigned long port) -{ - volatile unsigned short *addr = sn_io_addr(port); - - *addr = val; -} - -/** - * sn_outl - write a word to a port - * @port: port to write to - * @val: value to write - * - * Writes @val to @port. - */ -void -sn_outl (unsigned int val, unsigned long port) -{ - volatile unsigned int *addr = sn_io_addr(port); - - *addr = val; -} - -EXPORT_SYMBOL(sn_inb); -EXPORT_SYMBOL(sn_inw); -EXPORT_SYMBOL(sn_inl); -EXPORT_SYMBOL(sn_outb); -EXPORT_SYMBOL(sn_outw); -EXPORT_SYMBOL(sn_outl); diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index 4bf411ccae9b6..8d58bfbc7bf91 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c @@ -1,7 +1,7 @@ /* - * Platform dependent support for SGI SN1 + * Platform dependent support for SGI SN * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -32,12 +32,12 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ -#include <linux/config.h> #include <linux/init.h> #include <linux/sched.h> #include <asm/current.h> #include <linux/irq.h> #include <linux/interrupt.h> +#include <linux/slab.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/sn/sgi.h> @@ -49,19 +49,25 @@ #include <asm/sn/pci/bridge.h> #include <asm/sn/pci/pciio.h> #include <asm/sn/pci/pciio_private.h> -#ifdef ajmtestintr #include <asm/sn/pci/pcibr.h> #include <asm/sn/pci/pcibr_private.h> -#endif /* ajmtestintr */ #include <asm/sn/sn_cpuid.h> #include <asm/sn/io.h> #include <asm/sn/intr.h> #include <asm/sn/addrs.h> #include <asm/sn/driver.h> #include <asm/sn/arch.h> -#include <asm/sn/nodepda.h> +#include <asm/sn/pda.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/bitops.h> int irq_to_bit_pos(int irq); +static void force_interrupt(int irq); +extern void pcibr_force_interrupt(pcibr_intr_t intr); +extern int sn_force_interrupt_flag; + + static unsigned int sn_startup_irq(unsigned int irq) @@ -87,49 +93,11 @@ sn_enable_irq(unsigned int irq) static void sn_ack_irq(unsigned int irq) { -#ifdef CONFIG_IA64_SGI_SN1 - int bit = -1; - unsigned long long intpend_val; - int subnode; -#endif -#ifdef CONFIG_IA64_SGI_SN2 unsigned long event_occurred, mask = 0; -#endif int nasid; irq = irq & 0xff; nasid = smp_physical_node_id(); -#ifdef CONFIG_IA64_SGI_SN1 - subnode = cpuid_to_subnode(smp_processor_id()); - if (irq == SGI_UART_IRQ) { - intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0); - if (intpend_val & (1L<<GFX_INTR_A) ) { - bit = GFX_INTR_A; - REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit); - } - if ( intpend_val & (1L<<GFX_INTR_B) ) { - bit = GFX_INTR_B; - REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit); - } - if (intpend_val & (1L<<PG_MIG_INTR) ) { - bit = PG_MIG_INTR; - REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit); - } - if (intpend_val & (1L<<CC_PEND_A)) { - bit = CC_PEND_A; - REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit); - } - if (intpend_val & (1L<<CC_PEND_B)) { - bit = CC_PEND_B; - REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit); - } - return; - } - bit = irq_to_bit_pos(irq); - REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit); -#endif - -#ifdef CONFIG_IA64_SGI_SN2 event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) ); if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) { mask |= (1 << SH_EVENT_OCCURRED_UART_INT_SHFT); @@ -144,34 +112,18 @@ sn_ack_irq(unsigned int irq) mask |= (1 << SH_EVENT_OCCURRED_II_INT1_SHFT); } HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS), mask ); -#endif + __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs); } static void sn_end_irq(unsigned int irq) { -#ifdef CONFIG_IA64_SGI_SN1 - unsigned long long intpend_val, mask = 0x70L; - int subnode; -#endif int nasid; -#ifdef CONFIG_IA64_SGI_SN2 + int ivec; unsigned long event_occurred; -#endif - irq = irq & 0xff; -#ifdef CONFIG_IA64_SGI_SN1 - if (irq == SGI_UART_IRQ) { - nasid = smp_physical_node_id(); - subnode = cpuid_to_subnode(smp_processor_id()); - intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0); - if (intpend_val & mask) { - platform_send_ipi(smp_processor_id(), SGI_UART_IRQ, IA64_IPI_DM_INT, 0); - } - } -#endif -#ifdef CONFIG_IA64_SGI_SN2 - if (irq == SGI_UART_VECTOR) { + ivec = irq & 0xff; + if (ivec == SGI_UART_VECTOR) { nasid = smp_physical_node_id(); event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) ); // If the UART bit is set here, we may have received an interrupt from the @@ -181,8 +133,9 @@ sn_end_irq(unsigned int irq) platform_send_ipi(smp_processor_id(), SGI_UART_VECTOR, IA64_IPI_DM_INT, 0); } } -#endif - + __clear_bit(ivec, (volatile void *)pda->sn_in_service_ivecs); + if (sn_force_interrupt_flag) + force_interrupt(irq); } static void @@ -191,7 +144,7 @@ sn_set_affinity_irq(unsigned int irq, unsigned long mask) } -struct hw_interrupt_type irq_type_iosapic_level = { +struct hw_interrupt_type irq_type_sn = { "SN hub", sn_startup_irq, sn_shutdown_irq, @@ -203,29 +156,17 @@ struct hw_interrupt_type irq_type_iosapic_level = { }; -#define irq_type_sn irq_type_iosapic_level -struct irq_desc *_sn_irq_desc[NR_CPUS]; - struct irq_desc * sn_irq_desc(unsigned int irq) { - int cpu = irq >> 8; - irq = irq & 0xff; + irq = SN_IVEC_FROM_IRQ(irq); - return(_sn_irq_desc[cpu] + irq); + return(_irq_desc + irq); } u8 sn_irq_to_vector(u8 irq) { - return(irq & 0xff); -} - -int gsi_to_vector(u32 irq) { - return irq & 0xff; -} - -int gsi_to_irq(u32 irq) { - return irq & 0xff; + return(irq); } unsigned int @@ -233,47 +174,24 @@ sn_local_vector_to_irq(u8 vector) { return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector)); } -void *kmalloc(size_t, int); - void sn_irq_init (void) { int i; irq_desc_t *base_desc = _irq_desc; - for (i=IA64_FIRST_DEVICE_VECTOR; i<NR_IVECS; i++) { + for (i=IA64_FIRST_DEVICE_VECTOR; i<NR_IRQS; i++) { if (base_desc[i].handler == &no_irq_type) { base_desc[i].handler = &irq_type_sn; } } } -void -sn_init_irq_desc(void) { - int i; - irq_desc_t *base_desc = _irq_desc, *p; - - for (i=0; i < NR_CPUS; i++) { - p = page_address(alloc_pages_node(local_nodeid, GFP_KERNEL, - get_order(sizeof(struct irq_desc) * NR_IVECS) ) ); - ASSERT(p); - memcpy(p, base_desc, sizeof(struct irq_desc) * NR_IVECS); - _sn_irq_desc[i] = p; - } -} - - int bit_pos_to_irq(int bit) { #define BIT_TO_IRQ 64 if (bit > 118) bit = 118; -#ifdef CONFIG_IA64_SGI_SN1 - if (bit >= GFX_INTR_A && bit <= CC_PEND_B) { - return SGI_UART_IRQ; - } -#endif - return bit + BIT_TO_IRQ; } @@ -285,53 +203,181 @@ irq_to_bit_pos(int irq) { return bit; } -#ifdef ajmtestintr - -#include <linux/timer.h> -struct timer_list intr_test_timer = TIMER_INITIALIZER(NULL, 0, 0); -int intr_test_icount[NR_IRQS]; -struct intr_test_reg_struct { - pcibr_soft_t pcibr_soft; - int slot; +struct pcibr_intr_list_t { + struct pcibr_intr_list_t *next; + pcibr_intr_t intr; }; -struct intr_test_reg_struct intr_test_registered[NR_IRQS]; + +static struct pcibr_intr_list_t **pcibr_intr_list; void -intr_test_handle_timer(unsigned long data) { +register_pcibr_intr(int irq, pcibr_intr_t intr) { + struct pcibr_intr_list_t *p = kmalloc(sizeof(struct pcibr_intr_list_t), GFP_KERNEL); + struct pcibr_intr_list_t *list; + int cpu = SN_CPU_FROM_IRQ(irq); + + if (pcibr_intr_list == NULL) { + pcibr_intr_list = kmalloc(sizeof(struct pcibr_intr_list_t *) * NR_IRQS, GFP_KERNEL); + if (pcibr_intr_list == NULL) panic("Could not allocate memory for pcibr_intr_list\n"); + memset( (void *)pcibr_intr_list, 0, sizeof(struct pcibr_intr_list_t *) * NR_IRQS); + } + if (pdacpu(cpu)->sn_last_irq < irq) { + pdacpu(cpu)->sn_last_irq = irq; + } + if (pdacpu(cpu)->sn_first_irq > irq) pdacpu(cpu)->sn_first_irq = irq; + if (!p) panic("Could not allocate memory for pcibr_intr_list_t\n"); + if ((list = pcibr_intr_list[irq])) { + while (list->next) list = list->next; + list->next = p; + p->next = NULL; + p->intr = intr; + } else { + pcibr_intr_list[irq] = p; + p->next = NULL; + p->intr = intr; + } +} + +void +force_polled_int(void) { int i; - bridge_t *bridge; - - for (i=0;i<NR_IRQS;i++) { - if (intr_test_registered[i].pcibr_soft) { - pcibr_soft_t pcibr_soft = intr_test_registered[i].pcibr_soft; - xtalk_intr_t intr = pcibr_soft->bs_intr[intr_test_registered[i].slot].bsi_xtalk_intr; - /* send interrupt */ - bridge = pcibr_soft->bs_base; - bridge->b_force_always[intr_test_registered[i].slot].intr = 1; + struct pcibr_intr_list_t *p; + + for (i=0; i<NR_IRQS;i++) { + p = pcibr_intr_list[i]; + while (p) { + if (p->intr){ + pcibr_force_interrupt(p->intr); + } + p = p->next; } } - del_timer(&intr_test_timer); - intr_test_timer.expires = jiffies + HZ/100; - add_timer(&intr_test_timer); } -void -intr_test_set_timer(void) { - intr_test_timer.expires = jiffies + HZ/100; - intr_test_timer.function = intr_test_handle_timer; - add_timer(&intr_test_timer); +static void +force_interrupt(int irq) { + struct pcibr_intr_list_t *p = pcibr_intr_list[irq]; + + while (p) { + if (p->intr) { + pcibr_force_interrupt(p->intr); + } + p = p->next; + } +} + +/* +Check for lost interrupts. If the PIC int_status reg. says that +an interrupt has been sent, but not handled, and the interrupt +is not pending in either the cpu irr regs or in the soft irr regs, +and the interrupt is not in service, then the interrupt may have +been lost. Force an interrupt on that pin. It is possible that +the interrupt is in flight, so we may generate a spurious interrupt, +but we should never miss a real lost interrupt. +*/ + +static void +sn_check_intr(int irq, pcibr_intr_t intr) { + unsigned long regval; + int irr_reg_num; + int irr_bit; + unsigned long irr_reg; + + + regval = intr->bi_soft->bs_base->p_int_status_64; + irr_reg_num = irq_to_vector(irq) / 64; + irr_bit = irq_to_vector(irq) % 64; + switch (irr_reg_num) { + case 0: + irr_reg = ia64_get_irr0(); + break; + case 1: + irr_reg = ia64_get_irr1(); + break; + case 2: + irr_reg = ia64_get_irr2(); + break; + case 3: + irr_reg = ia64_get_irr3(); + break; + } + if (!test_bit(irr_bit, &irr_reg) ) { + if (!test_bit(irq, pda->sn_soft_irr) ) { + if (!test_bit(irq, pda->sn_in_service_ivecs) ) { + regval &= 0xff; + if (intr->bi_ibits & regval & intr->bi_last_intr) { + regval &= ~(intr->bi_ibits & regval); + pcibr_force_interrupt(intr); + } + } + } + } + intr->bi_last_intr = regval; } void -intr_test_register_irq(int irq, pcibr_soft_t pcibr_soft, int slot) { - irq = irq & 0xff; - intr_test_registered[irq].pcibr_soft = pcibr_soft; - intr_test_registered[irq].slot = slot; +sn_lb_int_war_check(void) { + int i; + + if (pda->sn_first_irq == 0) return; + for (i=pda->sn_first_irq; + i <= pda->sn_last_irq; i++) { + struct pcibr_intr_list_t *p = pcibr_intr_list[i]; + if (p == NULL) { + continue; + } + while (p) { + sn_check_intr(i, p->intr); + p = p->next; + } + } +} + +static inline int +sn_get_next_bit(void) { + int i; + int bit; + + for (i = 3; i >= 0; i--) { + if (pda->sn_soft_irr[i] != 0) { + bit = (i * 64) + __ffs(pda->sn_soft_irr[i]); + __change_bit(bit, (volatile void *)pda->sn_soft_irr); + return(bit); + } + } + return IA64_SPURIOUS_INT_VECTOR; } void -intr_test_handle_intr(int irq, void *junk, struct pt_regs *morejunk) { - intr_test_icount[irq]++; - printk("RECEIVED %d INTERRUPTS ON IRQ %d\n",intr_test_icount[irq], irq); +sn_set_tpr(int vector) { + if (vector > IA64_LAST_DEVICE_VECTOR || vector < IA64_FIRST_DEVICE_VECTOR) { + ia64_set_tpr(vector); + } else { + ia64_set_tpr(IA64_LAST_DEVICE_VECTOR); + } +} + +static inline void +sn_get_all_ivr(void) { + int vector; + + vector = ia64_get_ivr(); + while (vector != IA64_SPURIOUS_INT_VECTOR) { + __set_bit(vector, (volatile void *)pda->sn_soft_irr); + ia64_eoi(); + if (vector > IA64_LAST_DEVICE_VECTOR) return; + vector = ia64_get_ivr(); + } +} + +int +sn_get_ivr(void) { + int vector; + + vector = sn_get_next_bit(); + if (vector == IA64_SPURIOUS_INT_VECTOR) { + sn_get_all_ivr(); + vector = sn_get_next_bit(); + } + return vector; } -#endif /* ajmtestintr */ diff --git a/arch/ia64/sn/kernel/llsc4.c b/arch/ia64/sn/kernel/llsc4.c deleted file mode 100644 index 38373739789d6..0000000000000 --- a/arch/ia64/sn/kernel/llsc4.c +++ /dev/null @@ -1,1044 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/smp.h> -#include <linux/kernel_stat.h> -#include <linux/mm.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/efi.h> -#include <asm/page.h> -#include <linux/threads.h> -#include <asm/sn/simulator.h> -#include <asm/sn/leds.h> - -#include "llsc4.h" - - -#ifdef STANDALONE -#include "lock.h" -#endif - -#ifdef INTTEST -static int inttest=0; -#endif - -#ifdef IA64_SEMFIX_INSN -#undef IA64_SEMFIX_INSN -#endif -#ifdef IA64_SEMFIX -#undef IA64_SEMFIX -#endif -# define IA64_SEMFIX_INSN -# define IA64_SEMFIX "" - -#define NOLOCK 0xdead -#define BGUARD(linei) (0xbbbb0000 | (linei)); -#define EGUARD(linei) (0xeeee0000 | (linei)); -#define GUARDLINE(v) ((v)&0xffff) - -/* - * Test parameter table for AUTOTEST - */ -typedef struct { - int passes; - int linecount; - int linepad; -} autotest_table_t; - -autotest_table_t autotest_table[] = { - {50000000, 2, 0x2b4 }, - {50000000, 16, 0, }, - {50000000, 16, 4, }, - {50000000, 128, 0x44 }, - {50000000, 128, 0x84 }, - {50000000, 128, 0x200 }, - {50000000, 128, 0x204 }, - {50000000, 128, 0x2b4 }, - {50000000, 2, 8*MB+0x2b4 }, - {50000000, 16, 8*MB+0 }, - {50000000, 16, 8*MB+4 }, - {50000000, 128, 8*MB+0x44 }, - {50000000, 128, 8*MB+0x84 }, - {50000000, 128, 8*MB+0x200 }, - {50000000, 128, 8*MB+0x204 }, - {50000000, 128, 8*MB+0x2b4 }, - {0}}; - -/* - * Array of virtual addresses available for test purposes. - */ - -typedef struct { - long vstart; - long vend; - long nextaddr; - long nextinit; - int wrapcount; -} memmap_t; - -#define MAPCHUNKS 128 -memmap_t memmap[MAPCHUNKS]; -int memmapx=0; - -typedef struct { - void *addr; - long data[16]; - long data_fc[16]; -} capture_line_t; - -typedef struct { - int size; - void *blockaddr; - void *shadaddr; - long blockdata[48]; - long shaddata[48]; - long blockdata_fc[48]; - long shaddata_fc[48]; - long synerr; -} capture_t; - -/* - * PORTING NOTE: revisit this statement. On hardware we put mbase at 0 and - * the rest of the tables have to start at 1MB to skip PROM tables. - */ -#define THREADPRIVATESZ() ((sizeof(threadprivate_t)+511)/512*512) -#define THREADPRIVATE(t) ((threadprivate_t*)(((long)mbase)+4096+t*THREADPRIVATESZ())) - -#define k_capture mbase->sk_capture -#define k_go mbase->sk_go -#define k_linecount mbase->sk_linecount -#define k_passes mbase->sk_passes -#define k_napticks mbase->sk_napticks -#define k_stop_on_error mbase->sk_stop_on_error -#define k_verbose mbase->sk_verbose -#define k_threadprivate mbase->sk_threadprivate -#define k_blocks mbase->sk_blocks -#define k_iter_msg mbase->sk_iter_msg -#define k_vv mbase->sk_vv -#define k_linepad mbase->sk_linepad -#define k_options mbase->sk_options -#define k_testnumber mbase->sk_testnumber -#define k_currentpass mbase->sk_currentpass - -static long blocks[MAX_LINECOUNT]; /* addresses of data blocks */ -static control_t *mbase; -static vint initialized=0; - -static unsigned int ran_conf_llsc(int); -static int rerr(capture_t *, char *, void *, void *, int, int, int, int, int, int); -static void dumpline(void *, char *, char *, void *, void *, int); -static int checkstop(int, int, uint); -static void spin(int); -static void capturedata(capture_t *, uint, void *, void *, int); -static int randn(uint max, uint *seed); -static uint zrandom (uint *zranseed); -static int set_lock(uint *, uint); -static int clr_lock(uint *, uint); -static void Speedo(void); - -int autotest_enabled=0; -static int llsctest_number=-1; -static int errstop_enabled=0; -static int fail_enabled=0; -static int l4_opt=0; -static int selective_trigger=0; -static int dump_block_addrs_opt=0; -static lock_t errlock=NOLOCK; -static private_t init_private[LLSC_MAXCPUS]; - -static int __init autotest_enable(char *str) -{ - autotest_enabled = 1; - return 1; -} -static int __init set_llscblkadr(char *str) -{ - dump_block_addrs_opt = 1; - return 1; -} -static int __init set_llscselt(char *str) -{ - selective_trigger = 1; - return 1; -} -static int __init set_llsctest(char *str) -{ - llsctest_number = simple_strtol(str, &str, 10); - if (llsctest_number < 0 || llsctest_number > 15) - llsctest_number = -1; - return 1; -} -static int __init set_llscerrstop(char *str) -{ - errstop_enabled = 1; - return 1; -} -static int __init set_llscfail(char *str) -{ - fail_enabled = 8; - return 1; -} -static int __init set_llscl4(char *str) -{ - l4_opt = 1; - return 1; -} - -static void print_params(void) -{ - printk ("********* Enter AUTOTEST facility on master cpu *************\n"); - printk (" Test options:\n"); - printk (" llsctest=<n>\t%d\tTest number to run (all = -1)\n", llsctest_number); - printk (" llscerrstop \t%s\tStop on error\n", errstop_enabled ? "on" : "off"); - printk (" llscfail \t%s\tForce a failure to test the trigger & error messages\n", fail_enabled ? "on" : "off"); - printk (" llscselt \t%s\tSelective triger on failures\n", selective_trigger ? "on" : "off"); - printk (" llscblkadr \t%s\tDump data block addresses\n", dump_block_addrs_opt ? "on" : "off"); - printk (" llscl4 \t%s\tRun only tests that evict from L4\n", l4_opt ? "on" : "off"); - printk (" SEMFIX: %s\n", IA64_SEMFIX); - printk ("\n"); -} -__setup("autotest", autotest_enable); -__setup("llsctest=", set_llsctest); -__setup("llscerrstop", set_llscerrstop); -__setup("llscfail", set_llscfail); -__setup("llscselt", set_llscselt); -__setup("llscblkadr", set_llscblkadr); -__setup("llscl4", set_llscl4); - - - -static inline int -set_lock(uint *lock, uint id) -{ - uint old; - old = cmpxchg_acq(lock, NOLOCK, id); - return (old == NOLOCK); -} - -static inline int -clr_lock(uint *lock, uint id) -{ - uint old; - old = cmpxchg_rel(lock, id, NOLOCK); - return (old == id); -} - -static inline void -init_lock(uint *lock) -{ - *lock = NOLOCK; -} - -/*------------------------------------------------------------------------+ -| Routine : ran_conf_llsc - ll/sc shared data test | -| Description: This test checks the coherency of shared data | -+------------------------------------------------------------------------*/ -static unsigned int -ran_conf_llsc(int thread) -{ - private_t pval; - share_t sval, sval2; - uint vv, linei, slinei, sharei, pass; - long t; - lock_t lockpat; - share_t *sharecopy; - long verbose, napticks, passes, linecount, lcount; - dataline_t *linep, *slinep; - int s, seed; - threadprivate_t *tp; - uint iter_msg, iter_msg_i=0; - int vv_mask; - int correct_errors; - int errs=0; - int stillbad; - capture_t capdata; - private_t *privp; - share_t *sharep; - - - linecount = k_linecount; - napticks = k_napticks; - verbose = k_verbose; - passes = k_passes; - iter_msg = k_iter_msg; - seed = (thread + 1) * 647; - tp = THREADPRIVATE(thread); - vv_mask = (k_vv>>((thread%16)*4)) & 0xf; - correct_errors = k_options&0xff; - - memset (&capdata, 0, sizeof(capdata)); - for (linei=0; linei<linecount; linei++) - tp->private[linei] = thread; - - for (pass = 1; passes == 0 || pass < passes; pass++) { - lockpat = (pass & 0x0fffffff) + (thread <<28); - if (lockpat == NOLOCK) - continue; - tp->threadpasses = pass; - if (checkstop(thread, pass, lockpat)) - return 0; - iter_msg_i++; - if (iter_msg && iter_msg_i > iter_msg) { - printk("Thread %d, Pass %d\n", thread, pass); - iter_msg_i = 0; - } - lcount = 0; - - /* - * Select line to perform operations on. - */ - linei = randn(linecount, &seed); - sharei = randn(2, &seed); - slinei = (linei + (linecount/2))%linecount; /* I don't like this - fix later */ - - linep = (dataline_t *)blocks[linei]; - slinep = (dataline_t *)blocks[slinei]; - if (sharei == 0) - sharecopy = &slinep->share0; - else - sharecopy = &slinep->share1; - - - vv = randn(4, &seed); - if ((vv_mask & (1<<vv)) == 0) - continue; - - if (napticks) { - t = randn(napticks, &seed); - udelay(t); - } - privp = &linep->private[thread]; - sharep = &linep->share[sharei]; - - switch(vv) { - case 0: - /* Read and verify private count on line. */ - pval = *privp; - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, tp->private[linei]); - if (pval != tp->private[linei]) { - capturedata(&capdata, pass, privp, NULL, sizeof(*privp)); - stillbad = (*privp != tp->private[linei]); - if (rerr(&capdata, "Private count", linep, slinep, thread, pass, linei, tp->private[linei], pval, stillbad)) { - return 1; - } - if (correct_errors) { - tp->private[linei] = *privp; - } - errs++; - } - break; - - case 1: - /* Read, verify, and increment private count on line. */ - pval = *privp; - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, tp->private[linei]); - if (pval != tp->private[linei]) { - capturedata(&capdata, pass, privp, NULL, sizeof(*privp)); - stillbad = (*privp != tp->private[linei]); - if (rerr(&capdata, "Private count & inc", linep, slinep, thread, pass, linei, tp->private[linei], pval, stillbad)) { - return 1; - } - errs++; - } - pval = (pval==255) ? 0 : pval+1; - *privp = pval; - tp->private[linei] = pval; - break; - - case 2: - /* Lock line, read and verify shared data. */ - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, *sharecopy); - lcount = 0; - while (LOCK(sharei) != 1) { - if (checkstop(thread, pass, lockpat)) - return 0; - if (lcount++>1000000) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, sizeof(lock_t)); - stillbad = (GETLOCK(sharei) != 0); - rerr(&capdata, "Shared data lock", linep, slinep, thread, pass, linei, 0, GETLOCK(sharei), stillbad); - return 1; - } - if ((lcount&0x3fff) == 0) - udelay(1000); - } - - sval = *sharep; - sval2 = *sharecopy; - if (pass > 12 && thread == 0 && fail_enabled == 1) - sval++; - if (sval != sval2) { - capturedata(&capdata, pass, sharep, sharecopy, sizeof(*sharecopy)); - stillbad = (*sharep != *sharecopy); - if (!stillbad && *sharep != sval && *sharecopy == sval2) - stillbad = 2; - if (rerr(&capdata, "Shared data", linep, slinep, thread, pass, linei, sval2, sval, stillbad)) { - return 1; - } - if (correct_errors) - *sharep = *sharecopy; - errs++; - } - - - if ( (s=UNLOCK(sharei)) != 1) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, 4); - stillbad = (GETLOCK(sharei) != lockpat); - if (rerr(&capdata, "Shared data unlock", linep, slinep, thread, pass, linei, lockpat, GETLOCK(sharei), stillbad)) - return 1; - if (correct_errors) - ZEROLOCK(sharei); - errs++; - } - break; - - case 3: - /* Lock line, read and verify shared data, modify shared data. */ - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, *sharecopy); - lcount = 0; - while (LOCK(sharei) != 1) { - if (checkstop(thread, pass, lockpat)) - return 0; - if (lcount++>1000000) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, sizeof(lock_t)); - stillbad = (GETLOCK(sharei) != 0); - rerr(&capdata, "Shared data lock & inc", linep, slinep, thread, pass, linei, 0, GETLOCK(sharei), stillbad); - return 1; - } - if ((lcount&0x3fff) == 0) - udelay(1000); - } - sval = *sharep; - sval2 = *sharecopy; - if (sval != sval2) { - capturedata(&capdata, pass, sharep, sharecopy, sizeof(*sharecopy)); - stillbad = (*sharep != *sharecopy); - if (!stillbad && *sharep != sval && *sharecopy == sval2) - stillbad = 2; - if (rerr(&capdata, "Shared data & inc", linep, slinep, thread, pass, linei, sval2, sval, stillbad)) { - return 1; - } - errs++; - } - - *sharep = lockpat; - *sharecopy = lockpat; - - - if ( (s=UNLOCK(sharei)) != 1) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, 4); - stillbad = (GETLOCK(sharei) != lockpat); - if (rerr(&capdata, "Shared data & inc unlock", linep, slinep, thread, pass, linei, thread, GETLOCK(sharei), stillbad)) - return 1; - if (correct_errors) - ZEROLOCK(sharei); - errs++; - } - break; - } - } - - return (errs > 0); -} - -static void -trigger_la(long val) -{ - long *p; - - p = (long*)0xc0000a0001000020L; /* PI_CPU_NUM */ - *p = val; -} - -static long -getsynerr(void) -{ - long err, *errp; - - errp = (long*)0xc0000e0000000340L; /* SYN_ERR */ - err = *errp; - if (err) - *errp = -1L; - return (err & ~0x60); -} - -static int -rerr(capture_t *cap, char *msg, void *lp, void *slp, int thread, int pass, int badlinei, int exp, int found, int stillbad) -{ - int cpu, i, linei; - long synerr; - int selt; - - - selt = selective_trigger && stillbad > 1 && - memcmp(cap->blockdata, cap->blockdata_fc, 128) != 0 && - memcmp(cap->shaddata, cap->shaddata_fc, 128) == 0; - if (selt) { - trigger_la(pass); - } else if (selective_trigger) { - k_go = ST_STOP; - return k_stop_on_error;; - } - - spin(1); - i = 100; - while (i && set_lock(&errlock, 1) != 1) { - spin(1); - i--; - } - printk ("\nDataError!: %-20s, test %ld, thread %d, line:%d, pass %d (0x%x), time %ld expected:%x, found:%x\n", - msg, k_testnumber, thread, badlinei, pass, pass, jiffies, exp, found); - - dumpline (lp, "Corrupted data", "D ", cap->blockaddr, cap->blockdata, cap->size); -#ifdef ZZZ - if (memcmp(cap->blockdata, cap->blockdata_fc, 128)) - dumpline (lp, "Corrupted data", "DF", cap->blockaddr, cap->blockdata_fc, cap->size); -#endif - - if (cap->shadaddr) { - dumpline (slp, "Shadow data", "S ", cap->shadaddr, cap->shaddata, cap->size); -#ifdef ZZZ - if (memcmp(cap->shaddata, cap->shaddata_fc, 128)) - dumpline (slp, "Shadow data", "SF", cap->shadaddr, cap->shaddata_fc, cap->size); -#endif - } - - printk("Threadpasses: "); - for (cpu=0,i=0; cpu<LLSC_MAXCPUS; cpu++) - if (k_threadprivate[cpu]->threadpasses) { - if (i && (i%8) == 0) - printk("\n : "); - printk(" %d:0x%x", cpu, k_threadprivate[cpu]->threadpasses); - i++; - } - printk("\n"); - - for (linei=0; linei<k_linecount; linei++) { - int slinei, g1linei, g2linei, g1err, g2err, sh0err, sh1err; - dataline_t *linep, *slinep; - - slinei = (linei + (k_linecount/2))%k_linecount; - linep = (dataline_t *)blocks[linei]; - slinep = (dataline_t *)blocks[slinei]; - - g1linei = GUARDLINE(linep->guard1); - g2linei = GUARDLINE(linep->guard2); - g1err = (g1linei != linei); - g2err = (g2linei != linei); - sh0err = (linep->share[0] != slinep->share0); - sh1err = (linep->share[1] != slinep->share1); - - if (g1err || g2err || sh0err || sh1err) { - printk("Line 0x%lx (%03d), %sG1 0x%lx (%03d), %sG2 0x%lx (%03d), %sSH0 %08x (%08x), %sSH1 %08x (%08x)\n", - blocks[linei], linei, - g1err ? "*" : " ", blocks[g1linei], g1linei, - g2err ? "*" : " ", blocks[g2linei], g2linei, - sh0err ? "*" : " ", linep->share[0], slinep->share0, - sh1err ? "*" : " ", linep->share[1], slinep->share1); - - - } - } - - printk("\nData was %sfixed by flushcache\n", (stillbad == 1 ? "**** NOT **** " : " ")); - synerr = getsynerr(); - if (synerr) - printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr); - spin(2); - printk("\n\n"); - clr_lock(&errlock, 1); - - if (errstop_enabled) { - local_irq_disable(); - while(1); - } - return k_stop_on_error; -} - - -static void -dumpline(void *lp, char *str1, char *str2, void *addr, void *data, int size) -{ - long *p; - int i, off; - - printk("%s at 0x%lx, size %d, block starts at 0x%lx\n", str1, (long)addr, size, (long)lp); - p = (long*) data; - for (i=0; i<48; i++, p++) { - if (i%8 == 0) printk("%2s", i==16 ? str2 : " "); - printk(" %016lx", *p); - if ((i&7)==7) printk("\n"); - } - printk(" "); - off = (((long)addr) ^ size) & 63L; - for (i=0; i<off+size; i++) { - printk("%s", (i>=off) ? "--" : " "); - if ((i%8) == 7) - printk(" "); - } - - off = ((long)addr) & 127; - printk(" (line %d)\n", 2+off/64+1); -} - - -static int -randn(uint max, uint *seedp) -{ - if (max == 1) - return(0); - else - return((int)(zrandom(seedp)>>10) % max); -} - - -static int -checkstop(int thread, int pass, uint lockpat) -{ - long synerr; - - if (k_go == ST_RUN) - return 0; - if (k_go == ST_STOP) - return 1; - - if (errstop_enabled) { - local_irq_disable(); - while(1); - } - synerr = getsynerr(); - spin(2); - if (k_go == ST_STOP) - return 1; - if (synerr) - printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr); - return 1; -} - - -static void -spin(int j) -{ - udelay(j * 500000); -} - -static void -capturedata(capture_t *cap, uint pass, void *blockaddr, void *shadaddr, int size) -{ - - if (!selective_trigger) - trigger_la (pass); - - memcpy (cap->blockdata, CACHEALIGN(blockaddr)-128, 3*128); - if (shadaddr) - memcpy (cap->shaddata, CACHEALIGN(shadaddr)-128, 3*128); - - if (k_stop_on_error) { - k_go = ST_ERRSTOP; - } - - cap->size = size; - cap->blockaddr = blockaddr; - cap->shadaddr = shadaddr; - - asm volatile ("fc %0" :: "r"(blockaddr) : "memory"); - ia64_sync_i(); - ia64_srlz_d(); - memcpy (cap->blockdata_fc, CACHEALIGN(blockaddr)-128, 3*128); - - if (shadaddr) { - asm volatile ("fc %0" :: "r"(shadaddr) : "memory"); - ia64_sync_i(); - ia64_srlz_d(); - memcpy (cap->shaddata_fc, CACHEALIGN(shadaddr)-128, 3*128); - } -} - -int zranmult = 0x48c27395; - -static uint -zrandom (uint *seedp) -{ - *seedp = (*seedp * zranmult) & 0x7fffffff; - return (*seedp); -} - - -void -set_autotest_params(void) -{ - static int testnumber=-1; - - if (llsctest_number >= 0) { - testnumber = llsctest_number; - } else { - testnumber++; - if (autotest_table[testnumber].passes == 0) { - testnumber = 0; - dump_block_addrs_opt = 0; - } - } - if (testnumber == 0 && l4_opt) testnumber = 9; - - k_passes = autotest_table[testnumber].passes; - k_linepad = autotest_table[testnumber].linepad; - k_linecount = autotest_table[testnumber].linecount; - k_testnumber = testnumber; - - if (IS_RUNNING_ON_SIMULATOR()) { - printk ("llsc start test %ld\n", k_testnumber); - k_passes = 1000; - } -} - - -static void -set_leds(int errs) -{ - unsigned char leds=0; - - /* - * Leds are: - * ppppeee- - * where - * pppp = test number - * eee = error count but top bit is stick - */ - - leds = ((errs&7)<<1) | ((k_testnumber&15)<<4) | (errs ? 0x08 : 0); - set_led_bits(leds, LED_MASK_AUTOTEST); -} - -static void -setup_block_addresses(void) -{ - int i, stride, memmapi; - dataline_t *dp; - long *ip, *ipe; - - - stride = k_linepad + sizeof(dataline_t); - memmapi = 0; - for (i=0; i<memmapx; i++) { - memmap[i].nextaddr = memmap[i].vstart; - memmap[i].nextinit = memmap[i].vstart; - memmap[i].wrapcount = 0; - } - - for (i=0; i<k_linecount; i++) { - blocks[i] = memmap[memmapi].nextaddr; - dp = (dataline_t*)blocks[i]; - memmap[memmapi].nextaddr += (stride & 0xffff); - if (memmap[memmapi].nextaddr + sizeof(dataline_t) >= memmap[memmapi].vend) { - memmap[memmapi].wrapcount++; - memmap[memmapi].nextaddr = memmap[memmapi].vstart + - memmap[memmapi].wrapcount * sizeof(dataline_t); - } - - ip = (long*)((memmap[memmapi].nextinit+7)&~7); - ipe = (long*)(memmap[memmapi].nextaddr+2*sizeof(dataline_t)+8); - while(ip <= ipe && ip < ((long*)memmap[memmapi].vend-8)) - *ip++ = (long)ip; - memmap[memmapi].nextinit = (long) ipe; - dp->guard1 = BGUARD(i); - dp->guard2 = EGUARD(i); - dp->lock[0] = dp->lock[1] = NOLOCK; - dp->share[0] = dp->share0 = 0x1111; - dp->share[1] = dp->share1 = 0x2222; - memcpy(dp->private, init_private, LLSC_MAXCPUS*sizeof(private_t)); - - - if (stride > 16384) { - memmapi++; - if (memmapi == memmapx) - memmapi = 0; - } - } - -} - -static void -dump_block_addrs(void) -{ - int i; - - printk("LLSC TestNumber %ld\n", k_testnumber); - - for (i=0; i<k_linecount; i++) { - printk(" %lx", blocks[i]); - if (i%4 == 3) - printk("\n"); - } - printk("\n"); -} - - -static void -set_thread_state(int cpuid, int state) -{ - if (k_threadprivate[cpuid]->threadstate == TS_KILLED) { - set_led_bits(LED_MASK_AUTOTEST, LED_MASK_AUTOTEST); - while(1); - } - k_threadprivate[cpuid]->threadstate = state; -} - -#define MINBLK (16*1024*1024) -static int -build_mem_map(unsigned long start, unsigned long end, void *arg) -{ - long lstart, lend; - long align = 8*MB; - - printk ("LLSC memmap: start 0x%lx, end 0x%lx, (0x%lx - 0x%lx)\n", - start, end, (long) virt_to_page(start), (long) virt_to_page(end-PAGE_SIZE)); - - if (memmapx >= MAPCHUNKS || (end-start) < MINBLK) - return 0; - - /* - * Start in the middle of the range & find the first non-free page in both directions - * from the midpoint. This is likely to be the bigest free block. - */ - lend = lstart = start + (end-start)/2; - while (lend < end && !PageReserved(virt_to_page(lend)) && virt_to_page(lend)->count.counter == 0) - lend += PAGE_SIZE; - lend -= PAGE_SIZE; - - while (lstart >= start && !PageReserved(virt_to_page(lstart)) && virt_to_page(lstart)->count.counter == 0) - lstart -= PAGE_SIZE; - lstart += PAGE_SIZE; - - lstart = (lstart + align -1) /align * align; - end = end / align * align; - if (lstart >= end) - return 0; - printk (" memmap: start 0x%lx, end 0x%lx\n", lstart, end); - - memmap[memmapx].vstart = lstart; - memmap[memmapx].vend = end; - memmapx++; - return 0; -} - -void int_test(void); - -int -llsc_main (int cpuid) -{ - int i, cpu, is_master, repeatcnt=0; - unsigned int preverr=0, errs=0, pass=0; - int automode=0; - -#ifdef INTTEST - if (inttest) - int_test(); -#endif - - if (!autotest_enabled) - return 0; - -#ifdef CONFIG_SMP - is_master = !smp_processor_id(); -#else - is_master = 1; -#endif - - - if (is_master) { - mbase = (control_t*) __get_free_pages(GFP_KERNEL, get_order(4096+THREADPRIVATESZ()*LLSC_MAXCPUS)); - printk("LLSC: mbase 0x%lx\n", (long)mbase); - print_params(); - if(!IS_RUNNING_ON_SIMULATOR()) - spin(10); - k_currentpass = 0; - k_go = ST_IDLE; - k_passes = DEF_PASSES; - k_napticks = DEF_NAPTICKS; - k_stop_on_error = DEF_STOP_ON_ERROR; - k_verbose = DEF_VERBOSE; - k_linecount = DEF_LINECOUNT; - k_iter_msg = DEF_ITER_MSG; - k_vv = DEF_VV; - k_linepad = DEF_LINEPAD; - k_blocks = (void*)blocks; - efi_memmap_walk(build_mem_map, 0); - -#ifdef CONFIG_IA64_SGI_AUTOTEST - automode = 1; -#endif - - for (i=0; i<LLSC_MAXCPUS; i++) { - k_threadprivate[i] = THREADPRIVATE(i); - memset(k_threadprivate[i], 0, sizeof(*k_threadprivate[i])); - init_private[i] = i; - } - mb(); - initialized = 1; - } else { - while (initialized == 0) - udelay(100); - } - -loop: - if (is_master) { - if (automode) { - if (!preverr || repeatcnt++ > 5) { - set_autotest_params(); - repeatcnt = 0; - } - } else { - while (k_go == ST_IDLE); - } - - k_go = ST_INIT; - if (k_linecount > MAX_LINECOUNT) k_linecount = MAX_LINECOUNT; - k_linecount = k_linecount & ~1; - setup_block_addresses(); - if (!preverr && dump_block_addrs_opt) - dump_block_addrs(); - - k_currentpass = pass++; - k_go = ST_RUN; - if (fail_enabled) - fail_enabled--; - - } else { - while (k_go != ST_RUN || k_currentpass != pass); - pass++; - } - - - set_leds(errs); - set_thread_state(cpuid, TS_RUNNING); - - errs += ran_conf_llsc(cpuid); - preverr = (k_go == ST_ERRSTOP); - - set_leds(errs); - set_thread_state(cpuid, TS_STOPPED); - - if (is_master) { - Speedo(); - for (i=0, cpu=0; cpu<LLSC_MAXCPUS; cpu++) { - while (k_threadprivate[cpu]->threadstate == TS_RUNNING) { - i++; - if (i == 10000) { - k_go = ST_STOP; - printk (" llsc master stopping test number %ld\n", k_testnumber); - } - if (i > 100000) { - k_threadprivate[cpu]->threadstate = TS_KILLED; - printk (" llsc: master killing cpuid %d, running test number %ld\n", - cpu, k_testnumber); - } - udelay(1000); - } - } - } - - goto loop; -} - - -static void -Speedo(void) -{ - static int i = 0; - - switch (++i%4) { - case 0: - printk("|\b"); - break; - case 1: - printk("\\\b"); - break; - case 2: - printk("-\b"); - break; - case 3: - printk("/\b"); - break; - } -} - -#ifdef INTTEST - -/* ======================================================================================================== - * - * Some test code to verify that interrupts work - * - * Add the following to the arch/ia64/kernel/smp.c after the comment "Reschedule callback" - * if (zzzprint_resched) printk(" cpu %d got interrupt\n", smp_processor_id()); - * - * Enable the code in arch/ia64/sn/sn1/smp.c to print sending IPIs. - * - */ - -static int __init set_inttest(char *str) -{ - inttest = 1; - autotest_enabled = 1; - - return 1; -} - -__setup("inttest=", set_inttest); - -int zzzprint_resched=0; - -void -int_test() { - int mycpu, cpu; - static volatile int control_cpu=0; - - mycpu = smp_processor_id(); - zzzprint_resched = 2; - - printk("Testing cross interrupts\n"); - - while (control_cpu != smp_num_cpus) { - if (mycpu == cpu_logical_map(control_cpu)) { - for (cpu=0; cpu<smp_num_cpus; cpu++) { - printk("Sending interrupt from %d to %d\n", mycpu, cpu_logical_map(cpu)); - udelay(IS_RUNNING_ON_SIMULATOR ? 10000 : 400000); - smp_send_reschedule(cpu_logical_map(cpu)); - udelay(IS_RUNNING_ON_SIMULATOR ? 10000 : 400000); - smp_send_reschedule(cpu_logical_map(cpu)); - udelay(IS_RUNNING_ON_SIMULATOR ? 10000 : 400000); - } - control_cpu++; - } - } - - zzzprint_resched = 1; - - if (mycpu == cpu_logical_map(smp_num_cpus-1)) { - printk("\nTight loop of cpu %d sending ints to cpu 0 (every 100 us)\n", mycpu); - udelay(IS_RUNNING_ON_SIMULATOR ? 1000 : 1000000); - __cli(); - while (1) { - smp_send_reschedule(0); - udelay(100); - } - - } - - while(1); -} -#endif diff --git a/arch/ia64/sn/kernel/llsc4.h b/arch/ia64/sn/kernel/llsc4.h deleted file mode 100644 index 854fa14267a1b..0000000000000 --- a/arch/ia64/sn/kernel/llsc4.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#ifdef STANDALONE -#include "lock.h" -#endif - - -#define DEF_NAPTICKS 0 -#define DEF_PASSES 0 -#define DEF_AUTO_PASSES 1000000 -#define DEF_STOP_ON_ERROR 1 -#define DEF_VERBOSE 0 -#define DEF_LINECOUNT 2 -#define DEF_ITER_MSG 0 -#define DEF_VV 0xffffffff -#define DEF_LINEPAD 0x234 - - - -#define LLSC_MAXCPUS 64 -#define CACHELINE 64 -#define MAX_LINECOUNT 1024 -#define K 1024 -#define MB (K*K) - - -#define uint unsigned int -#define ushort unsigned short -#define uchar unsigned char -#define vint volatile int -#define vlong volatile long - -#define LOCKADDR(i) &linep->lock[(i)] -#define LOCK(i) set_lock(LOCKADDR(i), lockpat) -#define UNLOCK(i) clr_lock(LOCKADDR(i), lockpat) -#define GETLOCK(i) *LOCKADDR(i) -#define ZEROLOCK(i) init_lock(LOCKADDR(i)) - -#define CACHEALIGN(a) ((char*)((long)(a) & ~127L)) - -typedef uint guard_t; -typedef uint lock_t; -typedef uint share_t; -typedef uchar private_t; - -typedef struct { - guard_t guard1; - lock_t lock[2]; - share_t share[2]; - private_t private[LLSC_MAXCPUS]; - share_t share0; - share_t share1; - guard_t guard2; -} dataline_t ; - - -#define LINEPAD k_linepad -#define LINESTRIDE (((sizeof(dataline_t)+CACHELINE-1)/CACHELINE)*CACHELINE + LINEPAD) - - -typedef struct { - vint threadstate; - uint threadpasses; - private_t private[MAX_LINECOUNT]; -} threadprivate_t; - -typedef struct { - vlong sk_go; /* 0=idle, 1=init, 2=run */ - long sk_linecount; - long sk_passes; - long sk_napticks; - long sk_stop_on_error; - long sk_verbose; - long sk_iter_msg; - long sk_vv; - long sk_linepad; - long sk_options; - long sk_testnumber; - vlong sk_currentpass; - void *sk_blocks; - threadprivate_t *sk_threadprivate[LLSC_MAXCPUS]; -} control_t; - -/* Run state (k_go) constants */ -#define ST_IDLE 0 -#define ST_INIT 1 -#define ST_RUN 2 -#define ST_STOP 3 -#define ST_ERRSTOP 4 - - -/* Threadstate constants */ -#define TS_STOPPED 0 -#define TS_RUNNING 1 -#define TS_KILLED 2 - - - -int llsc_main (int cpuid); - diff --git a/arch/ia64/sn/kernel/machvec.c b/arch/ia64/sn/kernel/machvec.c index 72a81f6f21d3a..010b0623b1f9d 100644 --- a/arch/ia64/sn/kernel/machvec.c +++ b/arch/ia64/sn/kernel/machvec.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -30,32 +30,5 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ -#include <linux/config.h> - -#ifdef CONFIG_IA64_SGI_SN1 -#define MACHVEC_PLATFORM_NAME sn1 -#define MACHVEC_PLATFORM_HEADER <asm/machvec_sn1.h> -#else CONFIG_IA64_SGI_SN1 -#define MACHVEC_PLATFORM_NAME sn2 -#define MACHVEC_PLATFORM_HEADER <asm/machvec_sn2.h> -#else -#error "unknown platform" -#endif - +#define MACHVEC_PLATFORM_NAME sn2 #include <asm/machvec_init.h> -#include <asm/io.h> -#include <linux/pci.h> -void* -sn_mk_io_addr_MACRO - -dma_addr_t -sn_pci_map_single_MACRO - -int -sn_pci_map_sg_MACRO - -unsigned long -sn_virt_to_phys_MACRO - -void * -sn_phys_to_virt_MACRO diff --git a/arch/ia64/sn/kernel/mca.c b/arch/ia64/sn/kernel/mca.c index cfbfa1c24aaa5..02a25836ebbb2 100644 --- a/arch/ia64/sn/kernel/mca.c +++ b/arch/ia64/sn/kernel/mca.c @@ -2,7 +2,7 @@ * File: mca.c * Purpose: SN specific MCA code. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -34,247 +34,101 @@ */ #include <linux/types.h> -#include <linux/init.h> -#include <linux/jiffies.h> -#include <linux/threads.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/smp_lock.h> -#include <linux/acpi.h> -#ifdef CONFIG_KDB -#include <linux/kdb.h> -#endif - -#include <asm/machvec.h> -#include <asm/page.h> -#include <asm/ptrace.h> -#include <asm/system.h> +#include <linux/kernel.h> +#include <linux/timer.h> +#include <asm/mca.h> #include <asm/sal.h> #include <asm/sn/sn_sal.h> -#include <asm/mca.h> -#include <asm/sn/mca.h> - -#include <asm/irq.h> -#include <asm/hw_irq.h> -#include <asm/smp.h> -#include <asm/sn/sn_cpuid.h> - -static char *shub_mmr_names[] = { - "sh_event_occurred", - "sh_first_error", - "sh_event_overflow", - -/* PI */ - "sh_pi_first_error", - "sh_pi_error_summary", - "sh_pi_error_overflow", - -/* PI HW */ - "sh_pi_error_detail_1", - "sh_pi_error_detail_2", - "sh_pi_hw_time_stamp", - -/* PI UCE */ - "sh_pi_uncorrected_detail_1", - "sh_pi_uncorrected_detail_2", - "sh_pi_uncorrected_detail_3", - "sh_pi_uncorrected_detail_4", - "sh_pi_uncor_time_stamp", - -/* PI CE */ - "sh_pi_corrected_detail_1", - "sh_pi_corrected_detail_2", - "sh_pi_corrected_detail_3", - "sh_pi_corrected_detail_4", - "sh_pi_cor_time_stamp", - -/* MD */ - "sh_mem_error_summary", - "sh_mem_error_overflow", -/* MD HW */ - "sh_misc_err_hdr_upper", - "sh_misc_err_hdr_lower", - "sh_md_dqlp_mmr_xperr_val", - "sh_md_dqlp_mmr_yperr_val", - "sh_md_dqrp_mmr_xperr_val", - "sh_md_dqrp_mmr_yperr_val", - "sh_md_hw_time_stamp", - -/* MD UCE */ - "sh_dir_uc_err_hdr_lower", - "sh_dir_uc_err_hdr_upper", - "sh_md_dqlp_mmr_xuerr1", - "sh_md_dqlp_mmr_xuerr2", - "sh_md_dqlp_mmr_yuerr1", - "sh_md_dqlp_mmr_yuerr2", - "sh_md_dqrp_mmr_xuerr1", - "sh_md_dqrp_mmr_xuerr2", - "sh_md_dqrp_mmr_yuerr1", - "sh_md_dqrp_mmr_yuerr2", - "sh_md_uncor_time_stamp", -/* MD CE */ - "sh_dir_cor_err_hdr_lower", - "sh_dir_cor_err_hdr_upper", - "sh_md_dqlp_mmr_xcerr1", - "sh_md_dqlp_mmr_xcerr2", - "sh_md_dqlp_mmr_ycerr1", - "sh_md_dqlp_mmr_ycerr2", - "sh_md_dqrp_mmr_xcerr1", - "sh_md_dqrp_mmr_xcerr2", - "sh_md_dqrp_mmr_ycerr1", - "sh_md_dqrp_mmr_ycerr2", - "sh_md_cor_time_stamp", -/* MD CE, UCE */ - "sh_md_dqls_mmr_xamopw_err", - "sh_md_dqrs_mmr_yamopw_err", -/* XN */ - "sh_xn_error_summary", - "sh_xn_first_error", - "sh_xn_error_overflow", - -/* XN HW */ - "sh_xniilb_error_summary", - "sh_xniilb_first_error", - "sh_xniilb_error_overflow", - "sh_xniilb_error_detail_1", - "sh_xniilb_error_detail_2", - "sh_xniilb_error_detail_3", - - "sh_ni0_error_summary_1", - "sh_ni0_first_error_1", - "sh_ni0_error_overflow_1", - - "sh_ni0_error_summary_2", - "sh_ni0_first_error_2", - "sh_ni0_error_overflow_2", - "sh_ni0_error_detail_1", - "sh_ni0_error_detail_2", - "sh_ni0_error_detail_3", +/* + * Interval for calling SAL to poll for errors that do NOT cause error + * interrupts. SAL will raise a CPEI if any errors are present that + * need to be logged. + */ +#define CPEI_INTERVAL (5*HZ) - "sh_ni1_error_summary_1", - "sh_ni1_first_error_1", - "sh_ni1_error_overflow_1", - "sh_ni1_error_summary_2", - "sh_ni1_first_error_2", - "sh_ni1_error_overflow_2", +struct timer_list sn_cpei_timer; +void sn_init_cpei_timer(void); - "sh_ni1_error_detail_1", - "sh_ni1_error_detail_2", - "sh_ni1_error_detail_3", - "sh_xn_hw_time_stamp", +/* + * print_hook + * + * This function is the callback routine that SAL calls to log error + * info for platform errors. + */ +static int +print_hook(const char *fmt, ...) +{ + static int newline=1; + char buf[400], *p; + va_list args; + int len=0; -/* XN HW & UCE & SBE */ - "sh_xnpi_error_summary", - "sh_xnpi_first_error", - "sh_xnpi_error_overflow", - "sh_xnpi_error_detail_1", - "sh_xnmd_error_summary", - "sh_xnmd_first_error", - "sh_xnmd_error_overflow", - "sh_xnmd_ecc_err_report", - "sh_xnmd_error_detail_1", + va_start(args, fmt); + if (newline) { + strcpy(buf, "+ "); + len += 2; + } + len += vsnprintf(buf+len, sizeof(buf)-len, fmt, args); + + /* Prefix each line with "+ " to be consistent with mca.c. */ + p = buf; + while ((p=strchr(p, '\n')) && *++p != '\0') { + memmove(p+2, p, 1+strlen(p)); + strncpy(p, "+ ", 2); + len += 2; + } + newline = (p != 0); -/* XN UCE */ - "sh_xn_uncorrected_detail_1", - "sh_xn_uncorrected_detail_2", - "sh_xn_uncorrected_detail_3", - "sh_xn_uncorrected_detail_4", - "sh_xn_uncor_time_stamp", + va_end(args); + printk("%s", buf); + return len; +} -/* XN CE */ - "sh_xn_corrected_detail_1", - "sh_xn_corrected_detail_2", - "sh_xn_corrected_detail_3", - "sh_xn_corrected_detail_4", - "sh_xn_cor_time_stamp", -/* LB HW */ - "sh_lb_error_summary", - "sh_lb_first_error", - "sh_lb_error_overflow", - "sh_lb_error_detail_1", - "sh_lb_error_detail_2", - "sh_lb_error_detail_3", - "sh_lb_error_detail_4", - "sh_lb_error_detail_5", - "sh_junk_error_status", -}; -void -sal_log_plat_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) +/* + * ia64_sn2_platform_plat_specific_err_print + * + * Called by the MCA handler to log platform-specific errors. + */ +void +ia64_sn2_platform_plat_specific_err_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) { - sal_log_plat_info_t *sh_info = (sal_log_plat_info_t *) p_data; - u64 *mmr_val = (u64 *)&(sh_info->shub_state); - char **mmr_name = shub_mmr_names; - int mmr_count = sizeof(sal_log_shub_state_t)>>3; + ia64_sn_plat_specific_err_print(print_hook, p_data - sect_len); +} - while(mmr_count) { - if(*mmr_val) { - prfunc("%-40s: %#016lx\n",*mmr_name, *mmr_val); - } - mmr_name++; - mmr_val++; - mmr_count--; - } -} -void -sn_cpei_handler(int irq, void *devid, struct pt_regs *regs) { +static void +sn_cpei_handler(int irq, void *devid, struct pt_regs *regs) +{ + /* + * this function's sole purpose is to call SAL when we receive + * a CE interrupt from SHUB or when the timer routine decides + * we need to call SAL to check for CEs. + */ - struct ia64_sal_retval isrv; -// this function's sole purpose is to call SAL when we receive -// a CE interrupt from SHUB or when the timer routine decides -// we need to call SAL to check for CEs. + /* CALL SAL_LOG_CE */ - // CALL SAL_LOG_CE - SAL_CALL(isrv, SN_SAL_LOG_CE, irq, 0, 0, 0, 0, 0, 0); + ia64_sn_plat_cpei_handler(); } -#include <linux/timer.h> -#define CPEI_INTERVAL (HZ/100) -struct timer_list sn_cpei_timer = TIMER_INITIALIZER(NULL, 0, 0); -void sn_init_cpei_timer(void); - -void +static void sn_cpei_timer_handler(unsigned long dummy) { - sn_cpei_handler(-1, NULL, NULL); - del_timer(&sn_cpei_timer); - sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; - add_timer(&sn_cpei_timer); + sn_cpei_handler(-1, NULL, NULL); + mod_timer(&sn_cpei_timer, jiffies + CPEI_INTERVAL); } void sn_init_cpei_timer() { - sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; + sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; sn_cpei_timer.function = sn_cpei_timer_handler; add_timer(&sn_cpei_timer); } - -#ifdef ajmtestceintr - -struct timer_list sn_ce_timer; - -void -sn_ce_timer_handler(long dummy) { - unsigned long *pi_ce_error_inject_reg = 0xc00000092fffff00; - - *pi_ce_error_inject_reg = 0x0000000000000100; - del_timer(&sn_ce_timer); - sn_ce_timer.expires = jiffies + CPEI_INTERVAL; - add_timer(&sn_ce_timer); -} - -sn_init_ce_timer() { - sn_ce_timer.expires = jiffies + CPEI_INTERVAL; - sn_ce_timer.function = sn_ce_timer_handler; - add_timer(&sn_ce_timer); -} -#endif /* ajmtestceintr */ diff --git a/arch/ia64/sn/kernel/misctest.c b/arch/ia64/sn/kernel/misctest.c deleted file mode 100644 index 974c95e6be175..0000000000000 --- a/arch/ia64/sn/kernel/misctest.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <asm/sn/sn_sal.h> -#include <asm/sn/sn_cpuid.h> -#include <asm/processor.h> -#include <asm/pgtable.h> -#include <asm/page.h> -#include <asm/timex.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/sn/intr.h> -#include <asm/hw_irq.h> -#include <asm/sn/leds.h> - -extern int autotest_enabled; -long mcatest=0, debug0, debug1, debug2, debug3; - -#define HDELAY(t) (IS_RUNNING_ON_SIMULATOR() ? udelay(1) : udelay(t)) - -/* - * mcatest - * mactest contains a decimal number (RPTT) where - * R - flag, if non zero, run forever - * - * P - identifies when to run the test - * 0 execute test at cpu 0 early init - * 1 execute test at cpu 0 idle - * 2 execute test at last (highest numbered) cpu idle - * 3 execute test on all cpus at idle - * - * TT- identifies test to run - * 01 = MCA via dup TLB dropin - * 02 = MCA via garbage address - * 03 = lfetch via garbage address - * 05 = INIT self - * 06 = INIT other cpu - * 07 = INIT non-existent cpu - * 10 = IPI stress test. Target cpu 0 - * 11 = IPI stress test. Target all cpus - * 12 = TLB stress test - * 13 = Park cpu (spinloop) - * 14 = One shot TLB test with tlb spinlock - * 15 = One shot TLB test - * 16 = One shot TLB test sync'ed with RTC - * 20 = set led to the cpuid & spin. - * 21 = Try mixed cache/uncached refs & see what happens - * 22 = Call SAL reboot - * 23 = Call PAL halt - */ -static int __init set_mcatest(char *str) -{ - int val; - get_option(&str, &val); - mcatest = val; - return 1; -} -__setup("mcatest=", set_mcatest); - -static int __init set_debug0(char *str) -{ - int val; - get_option(&str, &val); - debug0 = val; - return 1; -} -__setup("debug0=", set_debug0); - -static int __init set_debug1(char *str) -{ - int val; - get_option(&str, &val); - debug1 = val; - return 1; -} -__setup("debug1=", set_debug1); - -static int __init set_debug2(char *str) -{ - int val; - get_option(&str, &val); - debug2 = val; - return 1; -} -__setup("debug2=", set_debug2); - -static int __init set_debug3(char *str) -{ - int val; - get_option(&str, &val); - debug3 = val; - return 1; -} -__setup("debug3=", set_debug3); - -static volatile int go; - -static void -do_sync(int pos) { - if (pos != 3) - return; - else if (smp_processor_id() == 0) - go = 1; - else - while (!go); -} - -static void -sgi_mcatest_bkpt(void) -{ -} - - -/* - * Optional test - * pos - 0 called from early init - * pos - called when cpu about to go idle (fully initialized - */ -void -sgi_mcatest(int pos) -{ - long spos, test, repeat; - int cpu, curcpu, i, n; - - //if (IS_RUNNING_ON_SIMULATOR()) mcatest=1323; - repeat = mcatest/1000; - spos = (mcatest/100)%10; - test = mcatest % 100; - curcpu = smp_processor_id(); - - if ( mcatest == 0 || !((pos == 0 && spos == 0) || - (pos == 1 && spos == 3) || - (pos == 1 && spos == 1 && curcpu == 0) || - (pos == 1 && spos == 2 && curcpu == smp_num_cpus-1))) - return; - -again: - if (test == 1 || test == 2 || test == 3) { - void zzzmca(int); - printk("CPU %d: About to cause unexpected MCA\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - zzzmca(test-1); - - HDELAY(100000); - } - - if (test == 4) { - long result, adrs[] = {0xe0021000009821e0UL, 0xc0003f3000000000UL, 0xc0000081101c0000UL, 0xc00000180e021004UL, 0xc00000180e022004UL, 0xc00000180e023004UL }; - long size[] = {1,2,4,8}; - int r, i, j, k; - - for (k=0; k<2; k++) { - for (i=0; i<6; i++) { - for (j=0; j<4; j++) { - printk("Probing 0x%lx, size %ld\n", adrs[i], size[j]); - result = -1; - r = ia64_sn_probe_io_slot (adrs[i], size[j], &result); - printk(" status %d, val 0x%lx\n", r, result); - udelay(100000); - } - } - } - - } - - if (test == 5) { - cpu = curcpu; - printk("CPU %d: About to send INIT to self (cpu %d)\n", curcpu, cpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); - - HDELAY(100000); - printk("CPU %d: Returned from INIT\n", curcpu); - } - - if (test == 6) { - cpu = curcpu ^ 1; - printk("CPU %d: About to send INIT to other cpu (cpu %d)\n", curcpu, cpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); - - HDELAY(100000); - printk("CPU %d: Done\n", curcpu); - } - - if (test == 7) { - printk("CPU %d: About to send INIT to non-existent cpu\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - sn_send_IPI_phys(0xffff, 0, IA64_IPI_DM_INIT); - - HDELAY(100000); - printk("CPU %d: Done\n", curcpu); - } - - if (test == 10) { - n = IS_RUNNING_ON_SIMULATOR() ? 10 : 10000000; - cpu = 0; - printk("CPU %d: IPI stress test. Target cpu 0\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - for (i=0; i<n; i++) - platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); - - HDELAY(100000); - printk("CPU %d: Done\n", curcpu); - } - - if (test == 11) { - n = IS_RUNNING_ON_SIMULATOR() ? 100 : 10000000; - printk("CPU %d: IPI stress test. Target all cpus\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - for (i=0; i<n; i++) - for (cpu=0; cpu<smp_num_cpus; cpu++) - if (smp_num_cpus > 2 && cpu != curcpu) - platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); - - HDELAY(100000); - printk("CPU %d: Done\n", curcpu); - } - - if (test == 12) { - long adr = 0xe002200000000000UL; - n = IS_RUNNING_ON_SIMULATOR() ? 1000 : 100000; - printk("CPU %d: TLB flush stress test\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - for (i=0; i<n; i++) - platform_global_tlb_purge(adr, adr+25*PAGE_SIZE, 14); - - HDELAY(100000); - printk("CPU %d: Done\n", curcpu); - } - - if (test == 13) { - printk("CPU %d: Park cpu in spinloop\n", curcpu); - while(1); - } - if (test == 14 || test == 15 || test == 16 || test == 17) { - long adr = 0xe002200000000000UL; - static int inited=0; - if (inited == 0) { - if (debug0 == 0) debug0 = 1; - repeat = 1; - do_sync(spos); - if (curcpu >= smp_num_cpus-2) { - printk("Parking cpu %d\n", curcpu); - local_irq_disable(); - while(1); - } else { - printk("Waiting cpu %d\n", curcpu); - HDELAY(1000000); - } - HDELAY(1000000); - inited = 1; - } - if (test == 16 || test == 17) { - unsigned long t, shift, mask; - mask = (smp_num_cpus > 16) ? 0x1f : 0xf; - shift = 25-debug1; - do { - t = get_cycles(); - if (IS_RUNNING_ON_SIMULATOR()) - t = (t>>8); - else - t = (t>>shift); - t = t & mask; - } while (t == curcpu); - do { - t = get_cycles(); - if (IS_RUNNING_ON_SIMULATOR()) - t = (t>>8); - else - t = (t>>shift); - t = t & mask; - } while (t != curcpu); - } - if(debug3) printk("CPU %d: One TLB start\n", curcpu); - if (test != 17) platform_global_tlb_purge(adr, adr+PAGE_SIZE*debug0, 14); - if(debug3) printk("CPU %d: One TLB flush done\n", curcpu); - } - if (test == 20) { - local_irq_disable(); - set_led_bits(smp_processor_id(), 0xff); - while(1); - } - if (test == 21) { - extern long ia64_mca_stack[]; - int i, n; - volatile long *p, *up; - p = (volatile long*)__imva(ia64_mca_stack); - up = (volatile long*)(__pa(p) | __IA64_UNCACHED_OFFSET); - - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ get data in cache\n"); - for (n=0, i=0; i<100; i++) - n += *(p+i); - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Make uncached refs to same data\n"); - for (n=0, i=0; i<100; i++) - n += *(up+i); - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ dirty the data via cached refs\n"); - for (n=0, i=0; i<100; i++) - *(p+i) = i; - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Make uncached refs to same data\n"); - for (n=0, i=0; i<100; i++) - n += *(up+i); - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Flushing cache\n"); - for (n=0, i=0; i<100; i++) - ia64_fc((void*)(p+i)); - printk("ZZZ done\n"); - } - if (test == 21) { - int i; - volatile long tb, t[10]; - for (i=0; i<10; i++) { - tb = debug3+ia64_get_itc(); - sgi_mcatest_bkpt(); - t[i] = ia64_get_itc() - tb; - } - for (i=0; i<10; i++) { - printk("ZZZ NULL 0x%lx\n", t[i]); - } - for (i=0; i<10; i++) { - tb = debug3+ia64_get_itc(); - ia64_pal_call_static(PAL_MC_DRAIN, 0, 0, 0, 0); - t[i] = ia64_get_itc() - tb; - } - for (i=0; i<10; i++) { - printk("ZZZ DRAIN 0x%lx\n", t[i]); - } - } - if (test == 22) { - extern void machine_restart(char*); - printk("ZZZ machine_restart\n"); - machine_restart(0); - } - if (test == 23) { - printk("ZZZ ia64_pal_halt_light\n"); - ia64_pal_halt_light(); - } - if (repeat) - goto again; - -} diff --git a/arch/ia64/sn/kernel/probe.c b/arch/ia64/sn/kernel/probe.c index 4b2cf42c2841e..e00518746db47 100644 --- a/arch/ia64/sn/kernel/probe.c +++ b/arch/ia64/sn/kernel/probe.c @@ -1,7 +1,7 @@ /* * Platform dependent support for IO probing. * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index 363a87497284e..8831bd886e36e 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -69,18 +69,17 @@ #include <asm/sn/bte.h> #include <asm/sn/clksupport.h> #include <asm/sn/sn_sal.h> - -#ifdef CONFIG_IA64_SGI_SN2 #include <asm/sn/sn2/shub.h> -#endif DEFINE_PER_CPU(struct pda_s, pda_percpu); +#define pxm_to_nasid(pxm) ((pxm)<<1) + extern void bte_init_node (nodepda_t *, cnodeid_t); extern void bte_init_cpu (void); extern void sn_timer_init (void); extern void (*ia64_mark_idle)(int); -extern void snidle(int); +void snidle(int); unsigned long sn_rtc_cycles_per_second; @@ -88,6 +87,8 @@ partid_t sn_partid = -1; char sn_system_serial_number_string[128]; u64 sn_partition_serial_number; +short physical_node_map[MAX_PHYSNODE_ID]; + /* * This is the address of the RRegs in the HSpace of the global * master. It is used by a hack in serial.c (serial_[in|out], @@ -96,21 +97,14 @@ u64 sn_partition_serial_number; * early_printk won't try to access the UART before * master_node_bedrock_address is properly calculated. */ -u64 master_node_bedrock_address = 0UL; +u64 master_node_bedrock_address; static void sn_init_pdas(char **); -extern struct irq_desc *_sn_irq_desc[]; - -#if defined(CONFIG_IA64_SGI_SN1) -extern synergy_da_t *Synergy_da_indr[]; -#endif static nodepda_t *nodepdaindr[MAX_COMPACT_NODES]; -#ifdef CONFIG_IA64_SGI_SN2 -irqpda_t *irqpdaindr[NR_CPUS]; -#endif /* CONFIG_IA64_SGI_SN2 */ +irqpda_t *irqpdaindr; /* @@ -137,29 +131,19 @@ struct screen_info sn_screen_info = { * running in the simulator. Note that passing zeroes in DRIVE_INFO * is sufficient (the IDE driver will autodetect the drive geometry). */ +#ifdef CONFIG_IA64_GENERIC +extern char drive_info[4*16]; +#else char drive_info[4*16]; - -/** - * sn_map_nr - return the mem_map entry for a given kernel address - * @addr: kernel address to query - * - * Finds the mem_map entry for the kernel address given. Used by - * virt_to_page() (asm-ia64/page.h), among other things. - */ -unsigned long -sn_map_nr (unsigned long addr) -{ - return BANK_MAP_NR(addr); -} +#endif /** * early_sn_setup - early setup routine for SN platforms * * Sets up an initial console to aid debugging. Intended primarily - * for bringup, it's only called if %BRINGUP and %CONFIG_IA64_EARLY_PRINTK - * are turned on. See start_kernel() in init/main.c. + * for bringup. See start_kernel() in init/main.c. */ -#if defined(CONFIG_IA64_EARLY_PRINTK) +#if defined(CONFIG_IA64_EARLY_PRINTK) || defined(CONFIG_IA64_SGI_SN_SIM) void __init early_sn_setup(void) @@ -197,21 +181,48 @@ early_sn_setup(void) } if ( IS_RUNNING_ON_SIMULATOR() ) { -#if defined(CONFIG_IA64_SGI_SN1) - master_node_bedrock_address = (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0); -#else master_node_bedrock_address = (u64)REMOTE_HUB(get_nasid(), SH_JUNK_BUS_UART0); -#endif printk(KERN_DEBUG "early_sn_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address); } } -#endif /* CONFIG_IA64_SGI_SN1 */ +#endif /* CONFIG_IA64_EARLY_PRINTK */ #ifdef CONFIG_IA64_MCA extern int platform_intr_list[]; #endif extern nasid_t master_nasid; +static int shub_1_1_found __initdata; + + +/* + * sn_check_for_wars + * + * Set flag for enabling shub specific wars + */ + +static inline int __init +is_shub_1_1(int nasid) +{ + unsigned long id; + int rev; + + id = REMOTE_HUB_L(nasid, SH_SHUB_ID); + rev = (id & SH_SHUB_ID_REVISION_MASK) >> SH_SHUB_ID_REVISION_SHFT; + return rev <= 2; +} + +static void __init +sn_check_for_wars(void) +{ + int cnode; + + for (cnode=0; cnode< numnodes; cnode++) + if (is_shub_1_1(cnodeid_to_nasid(cnode))) + shub_1_1_found = 1; +} + + /** * sn_setup - SN platform setup routine @@ -225,8 +236,18 @@ void __init sn_setup(char **cmdline_p) { long status, ticks_per_sec, drift; - int i; + int pxm; int major = sn_sal_rev_major(), minor = sn_sal_rev_minor(); + extern void io_sh_swapper(int, int); + extern nasid_t get_master_baseio_nasid(void); + extern void sn_cpu_init(void); + + MAX_DMA_ADDRESS = PAGE_OFFSET + MAX_PHYS_MEMORY; + + memset(physical_node_map, -1, sizeof(physical_node_map)); + for (pxm=0; pxm<MAX_PXM_DOMAINS; pxm++) + if (pxm_to_nid_map[pxm] != -1) + physical_node_map[pxm_to_nasid(pxm)] = pxm_to_nid_map[pxm]; printk("SGI SAL version %x.%02x\n", major, minor); @@ -239,23 +260,13 @@ sn_setup(char **cmdline_p) "%x.%02x\n", SN_SAL_MIN_MAJOR, SN_SAL_MIN_MINOR); panic("PROM version too old\n"); } -#ifdef CONFIG_PCI -#ifdef CONFIG_IA64_SGI_SN2 - { - extern void io_sh_swapper(int, int); - io_sh_swapper(get_nasid(), 0); - } -#endif + + io_sh_swapper(get_nasid(), 0); master_nasid = get_nasid(); (void)get_console_nasid(); -#ifndef CONFIG_IA64_SGI_SN1 - { - extern nasid_t get_master_baseio_nasid(void); - (void)get_master_baseio_nasid(); - } -#endif -#endif /* CONFIG_PCI */ + (void)get_master_baseio_nasid(); + status = ia64_sal_freq_base(SAL_FREQ_BASE_REALTIME_CLOCK, &ticks_per_sec, &drift); if (status != 0 || ticks_per_sec < 100000) { printk(KERN_WARNING "unable to determine platform RTC clock frequency, guessing.\n"); @@ -265,19 +276,12 @@ sn_setup(char **cmdline_p) else sn_rtc_cycles_per_second = ticks_per_sec; - for (i=0;i<NR_CPUS;i++) - _sn_irq_desc[i] = _irq_desc; - platform_intr_list[ACPI_INTERRUPT_CPEI] = IA64_PCE_VECTOR; if ( IS_RUNNING_ON_SIMULATOR() ) { -#ifdef CONFIG_IA64_SGI_SN2 master_node_bedrock_address = (u64)REMOTE_HUB(get_nasid(), SH_JUNK_BUS_UART0); -#else - master_node_bedrock_address = (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0); -#endif printk(KERN_DEBUG "sn_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address); } @@ -287,6 +291,10 @@ sn_setup(char **cmdline_p) */ sn_init_pdas(cmdline_p); + /* + * Check for WARs. + */ + sn_check_for_wars(); /* * For the bootcpu, we do this here. All other cpus will make the @@ -300,11 +308,6 @@ sn_setup(char **cmdline_p) #endif screen_info = sn_screen_info; - /* - * Turn off "floating-point assist fault" warnings by default. - */ - current->thread.flags |= IA64_THREAD_FPEMU_NOPRINT; - sn_timer_init(); ia64_mark_idle = &snidle; @@ -324,22 +327,19 @@ sn_init_pdas(char **cmdline_p) * Make sure that the PDA fits entirely in the same page as the * cpu_data area. */ - if ( (((unsigned long)pda & ~PAGE_MASK) + sizeof(pda_t)) > PAGE_SIZE) + if ((((unsigned long)pda & (~PAGE_MASK)) + sizeof(pda_t)) > PAGE_SIZE) panic("overflow of cpu_data page"); + memset(pda->cnodeid_to_nasid_table, -1, sizeof(pda->cnodeid_to_nasid_table)); + for (cnode=0; cnode<numnodes; cnode++) + pda->cnodeid_to_nasid_table[cnode] = pxm_to_nasid(nid_to_pxm_map[cnode]); + /* * Allocate & initalize the nodepda for each node. */ for (cnode=0; cnode < numnodes; cnode++) { nodepdaindr[cnode] = alloc_bootmem_node(NODE_DATA(cnode), sizeof(nodepda_t)); memset(nodepdaindr[cnode], 0, sizeof(nodepda_t)); - -#if defined(CONFIG_IA64_SGI_SN1) - Synergy_da_indr[cnode * 2] = (synergy_da_t *) alloc_bootmem_node(NODE_DATA(cnode), sizeof(synergy_da_t)); - Synergy_da_indr[cnode * 2 + 1] = (synergy_da_t *) alloc_bootmem_node(NODE_DATA(cnode), sizeof(synergy_da_t)); - memset(Synergy_da_indr[cnode * 2], 0, sizeof(synergy_da_t)); - memset(Synergy_da_indr[cnode * 2 + 1], 0, sizeof(synergy_da_t)); -#endif } /* @@ -348,7 +348,7 @@ sn_init_pdas(char **cmdline_p) for (cnode=0; cnode < numnodes; cnode++) memcpy(nodepdaindr[cnode]->pernode_pdaindr, nodepdaindr, sizeof(nodepdaindr)); -#ifdef CONFIG_PCI + /* * Set up IO related platform-dependent nodepda fields. * The following routine actually sets up the hubinfo struct @@ -358,7 +358,6 @@ sn_init_pdas(char **cmdline_p) init_platform_nodepda(nodepdaindr[cnode], cnode); bte_init_node (nodepdaindr[cnode], cnode); } -#endif } /** @@ -373,7 +372,11 @@ sn_init_pdas(char **cmdline_p) void __init sn_cpu_init(void) { - int cpuid, cpuphyid, nasid, nodeid, slice; + int cpuid; + int cpuphyid; + int nasid; + int slice; + int cnode, i; /* * The boot cpu makes this call again after platform initialization is @@ -385,14 +388,43 @@ sn_cpu_init(void) cpuid = smp_processor_id(); cpuphyid = ((ia64_get_lid() >> 16) & 0xffff); nasid = cpu_physical_id_to_nasid(cpuphyid); - nodeid = cpu_to_node_map[cpuphyid]; + cnode = nasid_to_cnodeid(nasid); slice = cpu_physical_id_to_slice(cpuphyid); - memset(pda, 0, sizeof(pda_t)); - pda->p_nodepda = nodepdaindr[nodeid]; + printk("CPU %d: nasid %d, slice %d, cnode %d\n", + smp_processor_id(), nasid, slice, cnode); + + memset(pda, 0, sizeof(pda)); + pda->p_nodepda = nodepdaindr[cnode]; + pda->led_address = (typeof(pda->led_address)) (LED0 + (slice<<LED_CPU_SHIFT)); + pda->led_state = LED_ALWAYS_SET; pda->hb_count = HZ/2; pda->hb_state = 0; pda->idle_flag = 0; + pda->shub_1_1_found = shub_1_1_found; + + memset(pda->cnodeid_to_nasid_table, -1, sizeof(pda->cnodeid_to_nasid_table)); + for (i=0; i<numnodes; i++) + pda->cnodeid_to_nasid_table[i] = pxm_to_nasid(nid_to_pxm_map[i]); + + if (local_node_data->active_cpu_count == 1) + nodepda->node_first_cpu = cpuid; + + + + /* + * We must use different memory allocators for first cpu (bootmem + * allocator) than for the other cpus (regular allocator). + */ + if (cpuid == 0) + irqpdaindr = alloc_bootmem_node(NODE_DATA(cpuid_to_cnodeid(cpuid)),sizeof(irqpda_t)); + + memset(irqpdaindr, 0, sizeof(irqpda_t)); + irqpdaindr->irq_flags[SGI_PCIBR_ERROR] = SN2_IRQ_SHARED; + irqpdaindr->irq_flags[SGI_PCIBR_ERROR] |= SN2_IRQ_RESERVED; + irqpdaindr->irq_flags[SGI_II_ERROR] = SN2_IRQ_SHARED; + irqpdaindr->irq_flags[SGI_II_ERROR] |= SN2_IRQ_RESERVED; + pda->pio_write_status_addr = (volatile unsigned long *) LOCAL_MMR_ADDR((slice < 2 ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ) ); pda->mem_write_status_addr = (volatile u64 *) @@ -400,89 +432,25 @@ sn_cpu_init(void) if (nodepda->node_first_cpu == cpuid) { int buddy_nasid; - buddy_nasid = cnodeid_to_nasid(local_nodeid == numnodes - 1 ? 0 : local_nodeid + 1); + buddy_nasid = cnodeid_to_nasid(numa_node_id() == numnodes-1 ? 0 : numa_node_id()+ 1); pda->pio_shub_war_cam_addr = (volatile unsigned long*)GLOBAL_MMR_ADDR(nasid, SH_PI_CAM_CONTROL); } bte_init_cpu(); } -#ifdef II_PRTE_TLB_WAR -long iiprt_lock[16*64] __cacheline_aligned; /* allow for NASIDs up to 64 */ -#endif - -#ifdef BUS_INT_WAR - -#include <asm/hw_irq.h> -#include <asm/sn/pda.h> - -void ia64_handle_irq (ia64_vector vector, struct pt_regs *regs); - -static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED; - -#define IRQCPU(irq) ((irq)>>8) - -void -sn_add_polled_interrupt(int irq, int interval) -{ - unsigned long flags, irq_cnt; - sn_poll_entry_t *irq_list; - - irq_list = pdacpu(IRQCPU(irq)).pda_poll_entries;; - - spin_lock_irqsave(&irq_lock, flags); - irq_cnt = pdacpu(IRQCPU(irq)).pda_poll_entry_count; - irq_list[irq_cnt].irq = irq; - irq_list[irq_cnt].interval = interval; - irq_list[irq_cnt].tick = interval; - pdacpu(IRQCPU(irq)).pda_poll_entry_count++; - spin_unlock_irqrestore(&irq_lock, flags); - - -} - -void -sn_delete_polled_interrupt(int irq) +void snidle(int idleness) { - unsigned long flags, i, irq_cnt; - sn_poll_entry_t *irq_list; - - irq_list = pdacpu(IRQCPU(irq)).pda_poll_entries; - - spin_lock_irqsave(&irq_lock, flags); - irq_cnt = pdacpu(IRQCPU(irq)).pda_poll_entry_count; - for (i=0; i<irq_cnt; i++) { - if (irq_list[i].irq == irq) { - irq_list[i] = irq_list[irq_cnt-1]; - pdacpu(IRQCPU(irq)).pda_poll_entry_count--; - break; + if (!idleness) { + if (pda->idle_flag == 0) { + set_led_bits(0, LED_CPU_ACTIVITY); } - } - spin_unlock_irqrestore(&irq_lock, flags); -} -void -sn_irq_poll(int cpu, int reason) -{ - unsigned long flags, i; - sn_poll_entry_t *irq_list; - - - ia64_handle_irq(IA64_IPI_VECTOR, 0); - - if (reason == 0) - return; - - irq_list = pda->pda_poll_entries; - - for (i=0; i<pda->pda_poll_entry_count; i++, irq_list++) { - if (--irq_list->tick <= 0) { - irq_list->tick = irq_list->interval; - local_irq_save(flags); - ia64_handle_irq(irq_to_vector(irq_list->irq), 0); - local_irq_restore(flags); - } + pda->idle_flag = 1; } -} + else { + set_led_bits(LED_CPU_ACTIVITY, LED_CPU_ACTIVITY); -#endif + pda->idle_flag = 0; + } +} diff --git a/arch/ia64/sn/kernel/sn1/Makefile b/arch/ia64/sn/kernel/sn1/Makefile deleted file mode 100644 index 65261dc37f5d2..0000000000000 --- a/arch/ia64/sn/kernel/sn1/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# -# arch/ia64/sn/kernel/sn1/Makefile -# -# Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2 of the GNU General Public License -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# Further, this software is distributed without any warranty that it is -# free of the rightful claim of any third person regarding infringement -# or the like. Any license provided herein, whether implied or -# otherwise, applies only to this software file. Patent licenses, if -# any, provided herein do not apply to combinations of this program with -# other software, or any other product whatsoever. -# -# You should have received a copy of the GNU General Public -# License along with this program; if not, write the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -# -# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, -# Mountain View, CA 94043, or: -# -# http://www.sgi.com -# -# For further information regarding this notice, see: -# -# http://oss.sgi.com/projects/GenInfo/NoticeExplan -# - - -EXTRA_CFLAGS := -DLITTLE_ENDIAN - -.S.s: - $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $< -.S.o: - $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< - -O_TARGET = sn1.o - -obj-y = cache.o error.o iomv.o synergy.o sn1_smp.o diff --git a/arch/ia64/sn/kernel/sn1/cache.c b/arch/ia64/sn/kernel/sn1/cache.c deleted file mode 100644 index c0894b03fca09..0000000000000 --- a/arch/ia64/sn/kernel/sn1/cache.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - * - */ - -#include <linux/kernel.h> -#include <asm/pgalloc.h> -#include <asm/sn/arch.h> -#include <asm/sn/sn_cpuid.h> -#include <asm/sn/sn1/synergy.h> -#include <asm/delay.h> - -#ifndef MB -#define MB (1024*1024) -#endif - -/* - * Lock for protecting SYN_TAG_DISABLE_WAY. - * Consider making this a per-FSB lock. - */ -static spinlock_t flush_lock = SPIN_LOCK_UNLOCKED; - -/** - * sn_flush_all_caches - flush a range of addresses from all caches (incl. L4) - * @flush_addr: identity mapped region 7 address to start flushing - * @bytes: number of bytes to flush - * - * Flush a range of addresses from all caches including L4. All addresses - * fully or partially contained within @flush_addr to @flush_addr + @bytes - * are flushed from the all caches. - */ -void -sn_flush_all_caches(long flush_addr, long bytes) -{ - ulong addr, baddr, eaddr, bitbucket; - int way, alias; - - /* - * Because of the way synergy implements "fc", this flushes the - * data from all caches on all cpus & L4's on OTHER FSBs. It also - * flushes both cpus on the local FSB. It does NOT flush it from - * the local FSB. - */ - flush_icache_range(flush_addr, flush_addr+bytes); - - /* - * Memory DIMMs are a minimum of 256MB and start on 256MB - * boundaries. Convert the start address to an address - * that is between +0MB & +128 of the same DIMM. - * Then add 8MB to skip the uncached MinState areas if the address - * is on the master node. - */ - if (bytes > SYNERGY_L4_BYTES_PER_WAY) - bytes = SYNERGY_L4_BYTES_PER_WAY; - baddr = TO_NODE(smp_physical_node_id(), PAGE_OFFSET + (flush_addr & (128*MB-1)) + 8*MB); - eaddr = (baddr+bytes+SYNERGY_BLOCK_SIZE-1) & ~(SYNERGY_BLOCK_SIZE-1); - baddr = baddr & ~(SYNERGY_BLOCK_SIZE-1); - - /* - * Now flush the local synergy. - */ - spin_lock(&flush_lock); - for(way=0; way<SYNERGY_L4_WAYS; way++) { - WRITE_LOCAL_SYNERGY_REG(SYN_TAG_DISABLE_WAY, 0xffL ^ (1L<<way)); - mb(); - for(alias=0; alias < 9; alias++) - for(addr=baddr; addr<eaddr; addr+=SYNERGY_BLOCK_SIZE) - bitbucket = *(volatile ulong *)(addr+alias*8*MB); - mb(); - } - WRITE_LOCAL_SYNERGY_REG(SYN_TAG_DISABLE_WAY, 0); - spin_unlock(&flush_lock); - -} - - diff --git a/arch/ia64/sn/kernel/sn1/error.c b/arch/ia64/sn/kernel/sn1/error.c deleted file mode 100644 index 16b68ae0012b4..0000000000000 --- a/arch/ia64/sn/kernel/sn1/error.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * SN1 Platform specific error Support - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> - -#include <asm/ptrace.h> -#include <linux/devfs_fs_kernel.h> -#include <asm/smp.h> -#include <asm/sn/sn_cpuid.h> -#include <asm/sn/sn1/bedrock.h> -#include <asm/sn/intr.h> -#include <asm/sn/addrs.h> - -/** - * snia_error_intr_handler - handle SN specific error interrupts - * @irq: error interrupt received - * @devid: device causing the interrupt - * @pt_regs: saved register state - * - * This routine is called when certain interrupts occur on SN systems. - * It will either recover from the situations that caused the interrupt - * or panic. - */ -void -snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs) -{ - unsigned long long intpend_val; - unsigned long long bit; - - switch (irq) { - case SGI_UART_IRQ: - /* - * This isn't really an error interrupt. We're just - * here because we have to do something with them. - * This is probably wrong, and this code will be - * removed. - */ - intpend_val = LOCAL_HUB_L(PI_INT_PEND0); - if ( (bit = ~(1L<<GFX_INTR_A)) == - (intpend_val & ~(1L<<GFX_INTR_A)) ) { - LOCAL_HUB_CLR_INTR(bit); - return; - } - if ( (bit = ~(1L<<GFX_INTR_B)) == - (intpend_val & ~(1L<<GFX_INTR_B)) ) { - LOCAL_HUB_CLR_INTR(bit); - return; - } - if ( (bit = ~(1L<<PG_MIG_INTR)) == - (intpend_val & ~(1L<<PG_MIG_INTR)) ) { - LOCAL_HUB_CLR_INTR(bit); - return; - } - if ( (bit = ~(1L<<UART_INTR)) == - (intpend_val & ~(1L<<UART_INTR)) ) { - LOCAL_HUB_CLR_INTR(bit); - return; - } - if ( (bit = ~(1L<<CC_PEND_A)) == - (intpend_val & ~(1L<<CC_PEND_A)) ) { - LOCAL_HUB_CLR_INTR(bit); - return; - } - if ( (bit = ~(1L<<CC_PEND_B)) == - (intpend_val & ~(1L<<CC_PEND_B)) ) { - LOCAL_HUB_CLR_INTR(bit); - return; - } - printk("Received SGI_UART_IRQ (65), but no intpend0 bits were set???\n"); - return; - case SGI_HUB_ERROR_IRQ: - /* - * These are mostly error interrupts of various - * sorts. We need to do more than panic here, but - * what the heck, this is bring up. - */ - intpend_val = LOCAL_HUB_L(PI_INT_PEND1); - - if ( (bit = ~(1L<<XB_ERROR)) == - (intpend_val & ~(1L<<XB_ERROR)) ) { - LOCAL_HUB_CLR_INTR(bit); - panic("RECEIVED XB_ERROR on cpu %d, cnode %d\n", - smp_processor_id(), - cpuid_to_cnodeid(smp_processor_id())); - } - if ( (bit = ~(1L<<LB_ERROR)) == - (intpend_val & ~(1L<<LB_ERROR)) ) { - LOCAL_HUB_CLR_INTR(bit); - panic("RECEIVED LB_ERROR on cpu %d, cnode %d\n", - smp_processor_id(), - cpuid_to_cnodeid(smp_processor_id())); - } - if ( (bit = ~(1L<<NACK_INT_A)) == - (intpend_val & ~(1L<<NACK_INT_A)) ) { - LOCAL_HUB_CLR_INTR(bit); - panic("RECEIVED NACK_INT_A on cpu %d, cnode %d\n", - smp_processor_id(), - cpuid_to_cnodeid(smp_processor_id())); - } - if ( (bit = ~(1L<<NACK_INT_B)) == - (intpend_val & ~(1L<<NACK_INT_B)) ) { - LOCAL_HUB_CLR_INTR(bit); - panic("RECEIVED NACK_INT_B on cpu %d, cnode %d\n", - smp_processor_id(), - cpuid_to_cnodeid(smp_processor_id())); - } - if ( (bit = ~(1L<<CLK_ERR_INTR)) == - (intpend_val & ~(1L<<CLK_ERR_INTR)) ) { - LOCAL_HUB_CLR_INTR(bit); - panic("RECEIVED CLK_ERR_INTR on cpu %d, cnode %d\n", - smp_processor_id(), - cpuid_to_cnodeid(smp_processor_id())); - } - if ( (bit = ~(1L<<COR_ERR_INTR_A)) == - (intpend_val & ~(1L<<COR_ERR_INTR_A)) ) { - LOCAL_HUB_CLR_INTR(bit); - panic("RECEIVED COR_ERR_INTR_A on cpu %d, cnode %d\n", - smp_processor_id(), - cpuid_to_cnodeid(smp_processor_id())); - } - if ( (bit = ~(1L<<COR_ERR_INTR_B)) == - (intpend_val & ~(1L<<COR_ERR_INTR_B)) ) { - LOCAL_HUB_CLR_INTR(bit); - panic("RECEIVED COR_ERR_INTR_B on cpu %d, cnode %d\n", - smp_processor_id(), - cpuid_to_cnodeid(smp_processor_id())); - } - if ( (bit = ~(1L<<MD_COR_ERR_INTR)) == - (intpend_val & ~(1L<<MD_COR_ERR_INTR)) ) { - LOCAL_HUB_CLR_INTR(bit); - panic("RECEIVED MD_COR_ERR_INTR on cpu %d, cnode %d\n", - smp_processor_id(), - cpuid_to_cnodeid(smp_processor_id())); - } - if ( (bit = ~(1L<<NI_ERROR_INTR)) == - (intpend_val & ~(1L<<NI_ERROR_INTR)) ) { - LOCAL_HUB_CLR_INTR(bit); - panic("RECEIVED NI_ERROR_INTR on cpu %d, cnode %d\n", - smp_processor_id(), - cpuid_to_cnodeid(smp_processor_id())); - } - if ( (bit = ~(1L<<MSC_PANIC_INTR)) == - (intpend_val & ~(1L<<MSC_PANIC_INTR)) ) { - LOCAL_HUB_CLR_INTR(bit); - panic("RECEIVED MSC_PANIC_INTR on cpu %d, cnode %d\n", - smp_processor_id(), - cpuid_to_cnodeid(smp_processor_id())); - } - printk("Received SGI_XB_ERROR_IRQ (182) but no intpend1 bits are set???\n"); - return; - default: - printk("Received invalid irq in snia_error_intr_handler()\n"); - } -} diff --git a/arch/ia64/sn/kernel/sn1/iomv.c b/arch/ia64/sn/kernel/sn1/iomv.c deleted file mode 100644 index 04bd87614c90c..0000000000000 --- a/arch/ia64/sn/kernel/sn1/iomv.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include <linux/pci.h> -#include <asm/io.h> -#include <asm/sn/simulator.h> -#include <asm/delay.h> -#include <asm/sn/pda.h> - -/** - * sn_io_addr - convert an in/out port to an i/o address - * @port: port to convert - * - * Legacy in/out instructions are converted to ld/st instructions - * on IA64. This routine will convert a port number into a valid - * SN i/o address. Used by sn_in*() and sn_out*(). - */ -void * -sn_io_addr(unsigned long port) -{ - if (!IS_RUNNING_ON_SIMULATOR()) { - return( (void *) (port | __IA64_UNCACHED_OFFSET)); - } else { - unsigned long io_base; - unsigned long addr; - - /* - * word align port, but need more than 10 bits - * for accessing registers in bedrock local block - * (so we don't do port&0xfff) - */ - if ((port >= 0x1f0 && port <= 0x1f7) || - port == 0x3f6 || port == 0x3f7) { - io_base = __IA64_UNCACHED_OFFSET | 0x00000FFFFC000000; - addr = io_base | ((port >> 2) << 12) | (port & 0xfff); - } else { - addr = __ia64_get_io_port_base() | ((port >> 2) << 2); - } - return(void *) addr; - } -} - -/** - * sn1_mmiob - I/O space memory barrier - * - * Acts as a memory mapped I/O barrier for platforms that queue writes to - * I/O space. This ensures that subsequent writes to I/O space arrive after - * all previous writes. For most ia64 platforms, this is a simple - * 'mf.a' instruction. For other platforms, mmiob() may have to read - * a chipset register to ensure ordering. - * - * On SN1, we wait for the PIO_WRITE_STATUS Bedrock register to clear. - */ -void -sn1_mmiob (void) -{ - (volatile unsigned long) (*pda.bedrock_rev_id); - while (!(volatile unsigned long) (*pda.pio_write_status_addr)) - udelay(5); -} diff --git a/arch/ia64/sn/kernel/sn1/sn1_smp.c b/arch/ia64/sn/kernel/sn1/sn1_smp.c deleted file mode 100644 index e24f97eba6576..0000000000000 --- a/arch/ia64/sn/kernel/sn1/sn1_smp.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * SN1 Platform specific SMP Support - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include <linux/config.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/spinlock.h> -#include <linux/threads.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/mmzone.h> - -#include <asm/processor.h> -#include <asm/irq.h> -#include <asm/sal.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/smp.h> -#include <asm/hw_irq.h> -#include <asm/current.h> -#include <asm/delay.h> -#include <asm/sn/sn_cpuid.h> - -/* - * The following structure is used to pass params thru smp_call_function - * to other cpus for flushing TLB ranges. - */ -typedef struct { - union { - struct { - unsigned long start; - unsigned long end; - unsigned long nbits; - unsigned int rid; - atomic_t unfinished_count; - } ptc; - char pad[SMP_CACHE_BYTES]; - }; -} ptc_params_t; - -#define NUMPTC 512 - -static ptc_params_t ptcParamArray[NUMPTC] __attribute__((__aligned__(128))); - -/* use separate cache lines on ptcParamsNextByCpu to avoid false sharing */ -static ptc_params_t *ptcParamsNextByCpu[NR_CPUS*16] __attribute__((__aligned__(128))); -static volatile ptc_params_t *ptcParamsEmpty __cacheline_aligned; - -/*REFERENCED*/ -static spinlock_t ptcParamsLock __cacheline_aligned = SPIN_LOCK_UNLOCKED; - -static int ptcInit = 0; -#ifdef PTCDEBUG -static int ptcParamsAllBusy = 0; /* debugging/statistics */ -static int ptcCountBacklog = 0; -static int ptcBacklog[NUMPTC+1]; -static char ptcParamsCounts[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); -static char ptcParamsResults[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); -#endif - -/* - * Make smp_send_flush_tlbsmp_send_flush_tlb() a weak reference, - * so that we get a clean compile with the ia64 patch without the - * actual SN1 specific code in arch/ia64/kernel/smp.c. - */ -extern void smp_send_flush_tlb (void) __attribute((weak)); - -/* - * The following table/struct is for remembering PTC coherency domains. It - * is also used to translate sapicid into cpuids. We don't want to start - * cpus unless we know their cache domain. - */ -#ifdef PTC_NOTYET -sn_sapicid_info_t sn_sapicid_info[NR_CPUS]; -#endif - -/** - * sn1_ptc_l_range - purge local translation cache - * @start: start of virtual address range - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Purges the range specified from the local processor's translation cache - * (as opposed to the translation registers). Note that more than the specified - * range *may* be cleared from the cache by some processors. - * - * This is probably not good enough, but I don't want to try to make it better - * until I get some statistics on a running system. At a minimum, we should only - * send IPIs to 1 processor in each TLB domain & have it issue a ptc.g on it's - * own FSB. Also, we only have to serialize per FSB, not globally. - * - * More likely, we will have to do some work to reduce the frequency of calls to - * this routine. - */ -static inline void -sn1_ptc_l_range(unsigned long start, unsigned long end, unsigned long nbits) -{ - do { - __asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); - start += (1UL << nbits); - } while (start < end); - ia64_srlz_d(); -} - -/** - * sn1_received_flush_tlb - cpu tlb flush routine - * - * Flushes the TLB of a given processor. - */ -void -sn1_received_flush_tlb(void) -{ - unsigned long start, end, nbits; - unsigned int rid, saved_rid; - int cpu = smp_processor_id(); - int result; - ptc_params_t *ptcParams; - - ptcParams = ptcParamsNextByCpu[cpu*16]; - if (ptcParams == ptcParamsEmpty) - return; - - do { - start = ptcParams->ptc.start; - saved_rid = (unsigned int) ia64_get_rr(start); - end = ptcParams->ptc.end; - nbits = ptcParams->ptc.nbits; - rid = ptcParams->ptc.rid; - - if (saved_rid != rid) { - ia64_set_rr(start, (unsigned long)rid); - ia64_srlz_d(); - } - - sn1_ptc_l_range(start, end, nbits); - - if (saved_rid != rid) - ia64_set_rr(start, (unsigned long)saved_rid); - - ia64_srlz_i(); - - result = atomic_dec(&ptcParams->ptc.unfinished_count); -#ifdef PTCDEBUG - { - int i = ptcParams-&ptcParamArray[0]; - ptcParamsResults[cpu][i] = (char) result; - ptcParamsCounts[cpu][i]++; - } -#endif /* PTCDEBUG */ - - if (++ptcParams == &ptcParamArray[NUMPTC]) - ptcParams = &ptcParamArray[0]; - - } while (ptcParams != ptcParamsEmpty); - - ptcParamsNextByCpu[cpu*16] = ptcParams; -} - -/** - * sn1_global_tlb_purge - flush a translation cache range on all processors - * @start: start of virtual address range to flush - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Flushes the translation cache of all processors from @start to @end. - */ -void -sn1_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) -{ - ptc_params_t *params; - ptc_params_t *next; - unsigned long irqflags; -#ifdef PTCDEBUG - ptc_params_t *nextnext; - int backlog = 0; -#endif - - if (smp_num_cpus == 1) { - sn1_ptc_l_range(start, end, nbits); - return; - } - - if (in_interrupt()) { - /* - * If at interrupt level and cannot get spinlock, - * then do something useful by flushing own tlbflush queue - * so as to avoid a possible deadlock. - */ - while (!spin_trylock(&ptcParamsLock)) { - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - udelay(10); /* take it easier on the bus */ - } - } else { - spin_lock(&ptcParamsLock); - } - - if (!ptcInit) { - int cpu; - ptcInit = 1; - memset(ptcParamArray, 0, sizeof(ptcParamArray)); - ptcParamsEmpty = &ptcParamArray[0]; - for (cpu=0; cpu<NR_CPUS; cpu++) - ptcParamsNextByCpu[cpu*16] = &ptcParamArray[0]; - -#ifdef PTCDEBUG - memset(ptcBacklog, 0, sizeof(ptcBacklog)); - memset(ptcParamsCounts, 0, sizeof(ptcParamsCounts)); - memset(ptcParamsResults, 0, sizeof(ptcParamsResults)); -#endif /* PTCDEBUG */ - } - - params = (ptc_params_t *) ptcParamsEmpty; - next = (ptc_params_t *) ptcParamsEmpty + 1; - if (next == &ptcParamArray[NUMPTC]) - next = &ptcParamArray[0]; - -#ifdef PTCDEBUG - nextnext = next + 1; - if (nextnext == &ptcParamArray[NUMPTC]) - nextnext = &ptcParamArray[0]; - - if (ptcCountBacklog) { - /* quick count of backlog */ - ptc_params_t *ptr; - - /* check the current pointer to the beginning */ - ptr = params; - while(--ptr >= &ptcParamArray[0]) { - if (atomic_read(&ptr->ptc.unfinished_count) == 0) - break; - ++backlog; - } - - if (backlog) { - /* check the end of the array */ - ptr = &ptcParamArray[NUMPTC]; - while (--ptr > params) { - if (atomic_read(&ptr->ptc.unfinished_count) == 0) - break; - ++backlog; - } - } - ptcBacklog[backlog]++; - } -#endif /* PTCDEBUG */ - - /* wait for the next entry to clear...should be rare */ - if (atomic_read(&next->ptc.unfinished_count) > 0) { -#ifdef PTCDEBUG - ptcParamsAllBusy++; - - if (atomic_read(&nextnext->ptc.unfinished_count) == 0) { - if (atomic_read(&next->ptc.unfinished_count) > 0) { - panic("\nnonzero next zero nextnext %lx %lx\n", - (long)next, (long)nextnext); - } - } -#endif - - /* it could be this cpu that is behind */ - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - - /* now we know it's not this cpu, so just wait */ - while (atomic_read(&next->ptc.unfinished_count) > 0) { - barrier(); - } - } - - params->ptc.start = start; - params->ptc.end = end; - params->ptc.nbits = nbits; - params->ptc.rid = (unsigned int) ia64_get_rr(start); - atomic_set(¶ms->ptc.unfinished_count, smp_num_cpus); - - /* The atomic_set above can hit memory *after* the update - * to ptcParamsEmpty below, which opens a timing window - * that other cpus can squeeze into! - */ - mb(); - - /* everything is ready to process: - * -- global lock is held - * -- new entry + 1 is free - * -- new entry is set up - * so now: - * -- update the global next pointer - * -- unlock the global lock - * -- send IPI to notify other cpus - * -- process the data ourselves - */ - ptcParamsEmpty = next; - spin_unlock(&ptcParamsLock); - smp_send_flush_tlb(); - - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - - /* Currently we don't think global TLB purges need to be atomic. - * All CPUs get sent IPIs, so if they haven't done the purge, - * they're busy with interrupts that are at the IPI level, which is - * priority 15. We're asserting that any code at that level - * shouldn't be using user TLB entries. To change this to wait - * for all the flushes to complete, enable the following code. - */ -#if defined(SN1_SYNCHRONOUS_GLOBAL_TLB_PURGE) || defined(BUS_INT_WAR) - /* this code is not tested */ - /* wait for the flush to complete */ - while (atomic_read(¶ms->ptc.unfinished_count) > 0) - barrier(); -#endif -} - -/** - * sn_send_IPI_phys - send an IPI to a Nasid and slice - * @physid: physical cpuid to receive the interrupt. - * @vector: command to send - * @delivery_mode: delivery mechanism - * - * Sends an IPI (interprocessor interrupt) to the processor specified by - * @physid - * - * @delivery_mode can be one of the following - * - * %IA64_IPI_DM_INT - pend an interrupt - * %IA64_IPI_DM_PMI - pend a PMI - * %IA64_IPI_DM_NMI - pend an NMI - * %IA64_IPI_DM_INIT - pend an INIT interrupt - */ -void -sn_send_IPI_phys(long physid, int vector, int delivery_mode) -{ - long *p; - long nasid, slice; - - static int off[4] = {0x1800080, 0x1800088, 0x1a00080, 0x1a00088}; - -#ifdef BUS_INT_WAR - if (vector != ap_wakeup_vector) { - return; - } -#endif - - nasid = cpu_physical_id_to_nasid(physid); - slice = cpu_physical_id_to_slice(physid); - - p = (long*)(0xc0000a0000000000LL | (nasid<<33) | off[slice]); - - mb(); - *p = (delivery_mode << 8) | (vector & 0xff); -} - - -/** - * sn1_send_IPI - send an IPI to a processor - * @cpuid: target of the IPI - * @vector: command to send - * @delivery_mode: delivery mechanism - * @redirect: redirect the IPI? - * - * Sends an IPI (interprocessor interrupt) to the processor specified by - * @cpuid. @delivery_mode can be one of the following - * - * %IA64_IPI_DM_INT - pend an interrupt - * %IA64_IPI_DM_PMI - pend a PMI - * %IA64_IPI_DM_NMI - pend an NMI - * %IA64_IPI_DM_INIT - pend an INIT interrupt - */ -void -sn1_send_IPI(int cpuid, int vector, int delivery_mode, int redirect) -{ - long physid; - - physid = cpu_physical_id(cpuid); - - sn_send_IPI_phys(physid, vector, delivery_mode); -} -#ifdef CONFIG_SMP - -#ifdef PTC_NOTYET -static void __init -process_sal_ptc_domain_info(ia64_sal_ptc_domain_info_t *di, int domain) -{ - ia64_sal_ptc_domain_proc_entry_t *pe; - int i, sapicid, cpuid; - - pe = __va(di->proc_list); - for (i=0; i<di->proc_count; i++, pe++) { - sapicid = id_eid_to_sapicid(pe->id, pe->eid); - cpuid = cpu_logical_id(sapicid); - sn_sapicid_info[cpuid].domain = domain; - sn_sapicid_info[cpuid].sapicid = sapicid; - } -} - - -static void __init -process_sal_desc_ptc(ia64_sal_desc_ptc_t *ptc) -{ - ia64_sal_ptc_domain_info_t *di; - int i; - - di = __va(ptc->domain_info); - for (i=0; i<ptc->num_domains; i++, di++) { - process_sal_ptc_domain_info(di, i); - } -} -#endif /* PTC_NOTYET */ - -/** - * init_sn1_smp_config - setup PTC domains per processor - */ -void __init -init_sn1_smp_config(void) -{ - if (!ia64_ptc_domain_info) { - printk("SMP: Can't find PTC domain info. Forcing UP mode\n"); - smp_num_cpus = 1; - return; - } - -#ifdef PTC_NOTYET - memset (sn_sapicid_info, -1, sizeof(sn_sapicid_info)); - process_sal_desc_ptc(ia64_ptc_domain_info); -#endif -} - -#else /* CONFIG_SMP */ - -void __init -init_sn1_smp_config(void) -{ - -#ifdef PTC_NOTYET - sn_sapicid_info[0].sapicid = hard_smp_processor_id(); -#endif -} - -#endif /* CONFIG_SMP */ diff --git a/arch/ia64/sn/kernel/sn1/synergy.c b/arch/ia64/sn/kernel/sn1/synergy.c deleted file mode 100644 index df31731bc73b9..0000000000000 --- a/arch/ia64/sn/kernel/sn1/synergy.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * SN1 Platform specific synergy Support - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/spinlock.h> -#include <linux/proc_fs.h> - -#include <asm/ptrace.h> -#include <linux/devfs_fs_kernel.h> -#include <asm/smp.h> -#include <asm/sn/sn_cpuid.h> -#include <asm/sn/sn1/bedrock.h> -#include <asm/sn/intr.h> -#include <asm/sn/addrs.h> -#include <asm/sn/nodepda.h> -#include <asm/sn/sn1/synergy.h> -#include <asm/sn/sndrv.h> - -int bit_pos_to_irq(int bit); -void setclear_mask_b(int irq, int cpuid, int set); -void setclear_mask_a(int irq, int cpuid, int set); -void * kmalloc(size_t size, int flags); - -static int synergy_perf_initialized = 0; - -void -synergy_intr_alloc(int bit, int cpuid) { - return; -} - -int -synergy_intr_connect(int bit, - int cpuid) -{ - int irq; - unsigned is_b; - - irq = bit_pos_to_irq(bit); - - is_b = (cpuid_to_slice(cpuid)) & 1; - if (is_b) { - setclear_mask_b(irq,cpuid,1); - setclear_mask_a(irq,cpuid, 0); - } else { - setclear_mask_a(irq, cpuid, 1); - setclear_mask_b(irq, cpuid, 0); - } - return 0; -} -void -setclear_mask_a(int irq, int cpuid, int set) -{ - int synergy; - int nasid; - int reg_num; - unsigned long mask; - unsigned long addr; - unsigned long reg; - unsigned long val; - int my_cnode, my_synergy; - int target_cnode, target_synergy; - - /* - * Perform some idiot checks .. - */ - if ( (irq < 0) || (irq > 255) || - (cpuid < 0) || (cpuid > 512) ) { - printk("clear_mask_a: Invalid parameter irq %d cpuid %d\n", irq, cpuid); - return; - } - - target_cnode = cpuid_to_cnodeid(cpuid); - target_synergy = cpuid_to_synergy(cpuid); - my_cnode = cpuid_to_cnodeid(smp_processor_id()); - my_synergy = cpuid_to_synergy(smp_processor_id()); - - reg_num = irq / 64; - mask = 1; - mask <<= (irq % 64); - switch (reg_num) { - case 0: - reg = VEC_MASK0A; - addr = VEC_MASK0A_ADDR; - break; - case 1: - reg = VEC_MASK1A; - addr = VEC_MASK1A_ADDR; - break; - case 2: - reg = VEC_MASK2A; - addr = VEC_MASK2A_ADDR; - break; - case 3: - reg = VEC_MASK3A; - addr = VEC_MASK3A_ADDR; - break; - default: - reg = addr = 0; - break; - } - if (my_cnode == target_cnode && my_synergy == target_synergy) { - // local synergy - val = READ_LOCAL_SYNERGY_REG(addr); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - WRITE_LOCAL_SYNERGY_REG(addr, val); - val = READ_LOCAL_SYNERGY_REG(addr); - } else { /* remote synergy */ - synergy = cpuid_to_synergy(cpuid); - nasid = cpuid_to_nasid(cpuid); - val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - REMOTE_SYNERGY_STORE(nasid, synergy, reg, val); - } -} - -void -setclear_mask_b(int irq, int cpuid, int set) -{ - int synergy; - int nasid; - int reg_num; - unsigned long mask; - unsigned long addr; - unsigned long reg; - unsigned long val; - int my_cnode, my_synergy; - int target_cnode, target_synergy; - - /* - * Perform some idiot checks .. - */ - if ( (irq < 0) || (irq > 255) || - (cpuid < 0) || (cpuid > 512) ) { - printk("clear_mask_b: Invalid parameter irq %d cpuid %d\n", irq, cpuid); - return; - } - - target_cnode = cpuid_to_cnodeid(cpuid); - target_synergy = cpuid_to_synergy(cpuid); - my_cnode = cpuid_to_cnodeid(smp_processor_id()); - my_synergy = cpuid_to_synergy(smp_processor_id()); - - reg_num = irq / 64; - mask = 1; - mask <<= (irq % 64); - switch (reg_num) { - case 0: - reg = VEC_MASK0B; - addr = VEC_MASK0B_ADDR; - break; - case 1: - reg = VEC_MASK1B; - addr = VEC_MASK1B_ADDR; - break; - case 2: - reg = VEC_MASK2B; - addr = VEC_MASK2B_ADDR; - break; - case 3: - reg = VEC_MASK3B; - addr = VEC_MASK3B_ADDR; - break; - default: - reg = addr = 0; - break; - } - if (my_cnode == target_cnode && my_synergy == target_synergy) { - // local synergy - val = READ_LOCAL_SYNERGY_REG(addr); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - WRITE_LOCAL_SYNERGY_REG(addr, val); - val = READ_LOCAL_SYNERGY_REG(addr); - } else { /* remote synergy */ - synergy = cpuid_to_synergy(cpuid); - nasid = cpuid_to_nasid(cpuid); - val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - REMOTE_SYNERGY_STORE(nasid, synergy, reg, val); - } -} - -/* - * Synergy perf stats. Multiplexed via timer_interrupt. - */ - -static int -synergy_perf_append(uint64_t modesel) -{ - int cnode; - nodepda_t *npdap; - synergy_perf_t *p; - int checked = 0; - int err = 0; - unsigned long flags; - - /* bit 45 is enable */ - modesel |= (1UL << 45); - - for (cnode=0; cnode < numnodes; cnode++) { - /* for each node, insert a new synergy_perf entry */ - if ((npdap = NODEPDA(cnode)) == NULL) { - printk("synergy_perf_append: cnode=%d NODEPDA(cnode)==NULL, nodepda=%p\n", cnode, (void *)nodepda); - continue; - } - - if (npdap->synergy_perf_enabled) { - /* user must disable counting to append new events */ - err = -EBUSY; - break; - } - - if (!checked && npdap->synergy_perf_data != NULL) { - checked = 1; - for (p = npdap->synergy_perf_first; ;) { - if (p->modesel == modesel) - return 0; /* event already registered */ - if ((p = p->next) == npdap->synergy_perf_first) - break; - } - } - - /* XX use kmem_alloc_node() when it is implemented */ - p = (synergy_perf_t *)kmalloc(sizeof(synergy_perf_t), GFP_KERNEL); - if ((((uint64_t)p) & 7UL) != 0) - BUG(); /* bad alignment */ - if (p == NULL) { - err = -ENOMEM; - break; - } - else { - memset(p, 0, sizeof(synergy_perf_t)); - p->modesel = modesel; - - spin_lock_irqsave(&npdap->synergy_perf_lock, flags); - if (npdap->synergy_perf_data == NULL) { - /* circular list */ - p->next = p; - npdap->synergy_perf_first = p; - npdap->synergy_perf_data = p; - } - else { - p->next = npdap->synergy_perf_data->next; - npdap->synergy_perf_data->next = p; - } - spin_unlock_irqrestore(&npdap->synergy_perf_lock, flags); - } - } - - return err; -} - -static void -synergy_perf_set_freq(int freq) -{ - int cnode; - nodepda_t *npdap; - - for (cnode=0; cnode < numnodes; cnode++) { - if ((npdap = NODEPDA(cnode)) != NULL) - npdap->synergy_perf_freq = freq; - } -} - -static void -synergy_perf_set_enable(int enable) -{ - int cnode; - nodepda_t *npdap; - - for (cnode=0; cnode < numnodes; cnode++) { - if ((npdap = NODEPDA(cnode)) != NULL) - npdap->synergy_perf_enabled = enable; - } - printk("NOTICE: synergy perf counting %sabled on all nodes\n", enable ? "en" : "dis"); -} - -static int -synergy_perf_size(nodepda_t *npdap) -{ - synergy_perf_t *p; - int n; - - if (npdap->synergy_perf_enabled == 0) { - /* no stats to return */ - return 0; - } - - spin_lock_irq(&npdap->synergy_perf_lock); - for (n=0, p = npdap->synergy_perf_first; p;) { - n++; - p = p->next; - if (p == npdap->synergy_perf_first) - break; - } - spin_unlock_irq(&npdap->synergy_perf_lock); - - /* bytes == n pairs of {event,counter} */ - return n * 2 * sizeof(uint64_t); -} - -static int -synergy_perf_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int cnode; - nodepda_t *npdap; - synergy_perf_t *p; - int intarg; - int fsb; - uint64_t longarg; - uint64_t *stats; - int n; - devfs_handle_t d; - arbitrary_info_t info; - - if ((d = devfs_get_handle_from_inode(inode)) == NULL) - return -ENODEV; - info = hwgraph_fastinfo_get(d); - - cnode = SYNERGY_PERF_INFO_CNODE(info); - fsb = SYNERGY_PERF_INFO_FSB(info); - npdap = NODEPDA(cnode); - - switch (cmd) { - case SNDRV_GET_SYNERGY_VERSION: - /* return int, version of data structure for SNDRV_GET_SYNERGYINFO */ - intarg = 1; /* version 1 */ - if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) - return -EFAULT; - break; - - case SNDRV_GET_INFOSIZE: - /* return int, sizeof buf needed for SYNERGY_PERF_GET_STATS */ - intarg = synergy_perf_size(npdap); - if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) - return -EFAULT; - break; - - case SNDRV_GET_SYNERGYINFO: - /* return array of event/value pairs, this node only */ - if ((intarg = synergy_perf_size(npdap)) <= 0) - return -ENODATA; - if ((stats = (uint64_t *)kmalloc(intarg, GFP_KERNEL)) == NULL) - return -ENOMEM; - spin_lock_irq(&npdap->synergy_perf_lock); - for (n=0, p = npdap->synergy_perf_first; p;) { - stats[n++] = p->modesel; - if (p->intervals > 0) - stats[n++] = p->counts[fsb] * p->total_intervals / p->intervals; - else - stats[n++] = 0; - p = p->next; - if (p == npdap->synergy_perf_first) - break; - } - spin_unlock_irq(&npdap->synergy_perf_lock); - - if (copy_to_user((void *)arg, stats, intarg)) { - kfree(stats); - return -EFAULT; - } - - kfree(stats); - break; - - case SNDRV_SYNERGY_APPEND: - /* reads 64bit event, append synergy perf event to all nodes */ - if (copy_from_user(&longarg, (void *)arg, sizeof(longarg))) - return -EFAULT; - return synergy_perf_append(longarg); - break; - - case SNDRV_GET_SYNERGY_STATUS: - /* return int, 1 if enabled else 0 */ - intarg = npdap->synergy_perf_enabled; - if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) - return -EFAULT; - break; - - case SNDRV_SYNERGY_ENABLE: - /* read int, if true enable counting else disable */ - if (copy_from_user(&intarg, (void *)arg, sizeof(intarg))) - return -EFAULT; - synergy_perf_set_enable(intarg); - break; - - case SNDRV_SYNERGY_FREQ: - /* read int, set jiffies per update */ - if (copy_from_user(&intarg, (void *)arg, sizeof(intarg))) - return -EFAULT; - if (intarg < 0 || intarg >= HZ) - return -EINVAL; - synergy_perf_set_freq(intarg); - break; - - default: - printk("Warning: invalid ioctl %d on synergy mon for cnode=%d fsb=%d\n", cmd, cnode, fsb); - return -EINVAL; - } - return(0); -} - -struct file_operations synergy_mon_fops = { - .ioctl = synergy_perf_ioctl, -}; - -void -synergy_perf_update(int cpu) -{ - nasid_t nasid; - cnodeid_t cnode; - struct nodepda_s *npdap; - - /* - * synergy_perf_initialized is set by synergy_perf_init() - * which is called last thing by sn_mp_setup(), i.e. well - * after nodepda has been initialized. - */ - if (!synergy_perf_initialized) - return; - - cnode = cpuid_to_cnodeid(cpu); - npdap = NODEPDA(cnode); - - if (npdap == NULL || cnode < 0 || cnode >= numnodes) - /* this should not happen: still in early io init */ - return; - -#if 0 - /* use this to check nodepda initialization */ - if (((uint64_t)npdap) & 0x7) { - printk("\nERROR on cpu %d : cnode=%d, npdap == %p, not aligned\n", cpu, cnode, npdap); - BUG(); - } -#endif - - if (npdap->synergy_perf_enabled == 0 || npdap->synergy_perf_data == NULL) { - /* Not enabled, or no events to monitor */ - return; - } - - if (npdap->synergy_inactive_intervals++ % npdap->synergy_perf_freq != 0) { - /* don't multiplex on every timer interrupt */ - return; - } - - /* - * Read registers for last interval and increment counters. - * Hold the per-node synergy_perf_lock so concurrent readers get - * consistent values. - */ - spin_lock_irq(&npdap->synergy_perf_lock); - - nasid = cpuid_to_nasid(cpu); - npdap->synergy_active_intervals++; - npdap->synergy_perf_data->intervals++; - npdap->synergy_perf_data->total_intervals = npdap->synergy_active_intervals; - - npdap->synergy_perf_data->counts[0] += 0xffffffffffUL & - REMOTE_SYNERGY_LOAD(nasid, 0, PERF_CNTR0_A); - - npdap->synergy_perf_data->counts[1] += 0xffffffffffUL & - REMOTE_SYNERGY_LOAD(nasid, 1, PERF_CNTR0_B); - - /* skip to next in circular list */ - npdap->synergy_perf_data = npdap->synergy_perf_data->next; - - spin_unlock_irq(&npdap->synergy_perf_lock); - - /* set the counter 0 selection modes for both A and B */ - REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTL0_A, npdap->synergy_perf_data->modesel); - REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTL0_B, npdap->synergy_perf_data->modesel); - - /* and reset the counter registers to zero */ - REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTR0_A, 0UL); - REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTR0_B, 0UL); -} - -void -synergy_perf_init(void) -{ - printk("synergy_perf_init(), counting is initially disabled\n"); - synergy_perf_initialized++; -} diff --git a/arch/ia64/sn/kernel/sn2/Makefile b/arch/ia64/sn/kernel/sn2/Makefile index 7309c25496613..a56bcb1e6cf5d 100644 --- a/arch/ia64/sn/kernel/sn2/Makefile +++ b/arch/ia64/sn/kernel/sn2/Makefile @@ -11,4 +11,5 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -obj-y += cache.o iomv.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o timer.o +obj-y += cache.o io.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o \ + prominfo_proc.o timer.o diff --git a/arch/ia64/sn/kernel/sn2/cache.c b/arch/ia64/sn/kernel/sn2/cache.c index af59e0fe3ddcd..f0cce9edc53d1 100644 --- a/arch/ia64/sn/kernel/sn2/cache.c +++ b/arch/ia64/sn/kernel/sn2/cache.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. * */ @@ -24,6 +24,5 @@ void sn_flush_all_caches(long flush_addr, long bytes) { flush_icache_range(flush_addr, flush_addr+bytes); + mb(); } - - diff --git a/arch/ia64/sn/kernel/sn2/io.c b/arch/ia64/sn/kernel/sn2/io.c index 9de12763a35f0..59423708d30ce 100644 --- a/arch/ia64/sn/kernel/sn2/io.c +++ b/arch/ia64/sn/kernel/sn2/io.c @@ -9,13 +9,8 @@ * we wrap the inlines from asm/ia64/sn/sn2/io.h here. */ -#include <linux/config.h> -#include <linux/types.h> - #include <asm/sn/sn2/io.h> -#ifdef CONFIG_IA64_GENERIC - unsigned int sn_inb (unsigned long port) { @@ -73,7 +68,7 @@ sn_readl (void *addr) unsigned long sn_readq (void *addr) { - return __sn_readq (addr) + return __sn_readq (addr); } @@ -94,5 +89,3 @@ asm ("__sn_readb = sn_readb"); asm ("__sn_readw = sn_readw"); asm ("__sn_readl = sn_readl"); asm ("__sn_readq = sn_readq"); - -#endif /* CONFIG_IA64_GENERIC */ diff --git a/arch/ia64/sn/kernel/sn2/iomv.c b/arch/ia64/sn/kernel/sn2/iomv.c deleted file mode 100644 index 4dd53594f5c07..0000000000000 --- a/arch/ia64/sn/kernel/sn2/iomv.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include <linux/pci.h> -#include <linux/module.h> -#include <asm/io.h> -#include <asm/delay.h> -#include <asm/sn/simulator.h> -#include <asm/sn/pda.h> -#include <asm/sn/sn_cpuid.h> - -/** - * sn_io_addr - convert an in/out port to an i/o address - * @port: port to convert - * - * Legacy in/out instructions are converted to ld/st instructions - * on IA64. This routine will convert a port number into a valid - * SN i/o address. Used by sn_in*() and sn_out*(). - */ -void * -sn_io_addr(unsigned long port) -{ - if (!IS_RUNNING_ON_SIMULATOR()) { - return( (void *) (port | __IA64_UNCACHED_OFFSET)); - } else { - unsigned long io_base; - unsigned long addr; - - /* - * word align port, but need more than 10 bits - * for accessing registers in bedrock local block - * (so we don't do port&0xfff) - */ - if ((port >= 0x1f0 && port <= 0x1f7) || - port == 0x3f6 || port == 0x3f7) { - io_base = (0xc000000fcc000000 | ((unsigned long)get_nasid() << 38)); - addr = io_base | ((port >> 2) << 12) | (port & 0xfff); - } else { - addr = __ia64_get_io_port_base() | ((port >> 2) << 2); - } - return(void *) addr; - } -} - -EXPORT_SYMBOL(sn_io_addr); - -/** - * sn_mmiob - I/O space memory barrier - * - * Acts as a memory mapped I/O barrier for platforms that queue writes to - * I/O space. This ensures that subsequent writes to I/O space arrive after - * all previous writes. For most ia64 platforms, this is a simple - * 'mf.a' instruction. For other platforms, mmiob() may have to read - * a chipset register to ensure ordering. - * - * On SN2, we wait for the PIO_WRITE_STATUS SHub register to clear. - * See PV 871084 for details about the WAR about zero value. - * - */ -void -sn_mmiob (void) -{ - while ((((volatile unsigned long) (*pda.pio_write_status_addr)) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != - SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) - udelay(1); -} diff --git a/arch/ia64/sn/kernel/sn2/prominfo_proc.c b/arch/ia64/sn/kernel/sn2/prominfo_proc.c new file mode 100644 index 0000000000000..f860679d5b12f --- /dev/null +++ b/arch/ia64/sn/kernel/sn2/prominfo_proc.c @@ -0,0 +1,361 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * Module to export the system's Firmware Interface Tables, including + * PROM revision numbers, in /proc + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/proc_fs.h> +#include <asm/io.h> +#include <asm/sn/simulator.h> + +/* to lookup nasids */ +#include <asm/sn/sn_cpuid.h> + +MODULE_DESCRIPTION("PROM version reporting for /proc"); +MODULE_AUTHOR("Chad Talbott"); +MODULE_LICENSE("GPL"); + +#undef DEBUG_PROMINFO + +#define TRACE_PROMINFO + +#if defined(DEBUG_PROMINFO) +# define DPRINTK(x...) printk(KERN_DEBUG x) +#else +# define DPRINTK(x...) +#endif + +#if defined(TRACE_PROMINFO) && defined(DEBUG_PROMINFO) +# if defined(__GNUC__) +# define TRACE() printk(KERN_DEBUG "%s:%d:%s\n", \ + __FILE__, __LINE__, __FUNCTION__) +# else +# define TRACE() printk(KERN_DEBUG "%s:%d\n", __LINE__, __FILE__) +# endif +#else +# define TRACE() +#endif + +/* Sub-regions determined by bits in Node Offset */ +#define LB_PROM_SPACE 0x0000000700000000ul /* Local LB PROM */ + +#define FIT_SIGNATURE 0x2020205f5449465ful +/* Standard Intel FIT entry types */ +#define FIT_ENTRY_FIT_HEADER 0x00 /* FIT header entry */ +#define FIT_ENTRY_PAL_B 0x01 /* PAL_B entry */ +/* Entries 0x02 through 0x0D reserved by Intel */ +#define FIT_ENTRY_PAL_A_PROC 0x0E /* Processor-specific PAL_A entry */ +#define FIT_ENTRY_PAL_A 0x0F /* PAL_A entry, same as... */ +#define FIT_ENTRY_PAL_A_GEN 0x0F /* ...Generic PAL_A entry */ +#define FIT_ENTRY_UNUSED 0x7F /* Unused (reserved by Intel?) */ +/* OEM-defined entries range from 0x10 to 0x7E. */ +#define FIT_ENTRY_SAL_A 0x10 /* SAL_A entry */ +#define FIT_ENTRY_SAL_B 0x11 /* SAL_B entry */ +#define FIT_ENTRY_SALRUNTIME 0x12 /* SAL runtime entry */ +#define FIT_ENTRY_EFI 0x1F /* EFI entry */ +#define FIT_ENTRY_FPSWA 0x20 /* embedded fpswa entry */ +#define FIT_ENTRY_VMLINUX 0x21 /* embedded vmlinux entry */ + +#define FIT_MAJOR_SHIFT (32 + 8) +#define FIT_MAJOR_MASK ((1 << 8) - 1) +#define FIT_MINOR_SHIFT 32 +#define FIT_MINOR_MASK ((1 << 8) - 1) + +#define FIT_MAJOR(q) \ + ((unsigned) ((q) >> FIT_MAJOR_SHIFT) & FIT_MAJOR_MASK) +#define FIT_MINOR(q) \ + ((unsigned) ((q) >> FIT_MINOR_SHIFT) & FIT_MINOR_MASK) + +#define FIT_TYPE_SHIFT (32 + 16) +#define FIT_TYPE_MASK ((1 << 7) - 1) + +#define FIT_TYPE(q) \ + ((unsigned) ((q) >> FIT_TYPE_SHIFT) & FIT_TYPE_MASK) + +#define FIT_ENTRY(type, maj, min, size) \ + ((((unsigned long)(maj) & FIT_MAJOR_MASK) << FIT_MAJOR_SHIFT) | \ + (((unsigned long)(min) & FIT_MINOR_MASK) << FIT_MINOR_SHIFT) | \ + (((unsigned long)(type) & FIT_TYPE_MASK) << FIT_TYPE_SHIFT) | \ + (size)) + +struct fit_type_map_t { + unsigned char type; + const char *name; +}; + +static const struct fit_type_map_t fit_entry_types[] = { + { FIT_ENTRY_FIT_HEADER, "FIT Header" }, + { FIT_ENTRY_PAL_A_GEN, "Generic PAL_A" }, + { FIT_ENTRY_PAL_A_PROC, "Processor-specific PAL_A" }, + { FIT_ENTRY_PAL_A, "PAL_A" }, + { FIT_ENTRY_PAL_B, "PAL_B" }, + { FIT_ENTRY_SAL_A, "SAL_A" }, + { FIT_ENTRY_SAL_B, "SAL_B" }, + { FIT_ENTRY_SALRUNTIME, "SAL runtime" }, + { FIT_ENTRY_EFI, "EFI" }, + { FIT_ENTRY_VMLINUX, "Embedded Linux" }, + { FIT_ENTRY_FPSWA, "Embedded FPSWA" }, + { FIT_ENTRY_UNUSED, "Unused" }, + { 0xff, "Error" }, +}; + +static const char * +fit_type_name(unsigned char type) +{ + struct fit_type_map_t const*mapp; + + for (mapp = fit_entry_types; mapp->type != 0xff; mapp++) + if (type == mapp->type) + return mapp->name; + + if ((type > FIT_ENTRY_PAL_A) && (type < FIT_ENTRY_UNUSED)) + return "OEM type"; + if ((type > FIT_ENTRY_PAL_B) && (type < FIT_ENTRY_PAL_A)) + return "Reserved"; + + return "Unknown type"; +} + +/* These two routines read the FIT table directly from the FLASH PROM + * on a specific node. The PROM can only be accessed using aligned 64 + * bit reads, so we do that and then shift and mask the result to get + * at each field. + */ +static int +dump_fit_entry(char *page, unsigned long *fentry) +{ + unsigned long q1, q2; + unsigned type; + + TRACE(); + + q1 = readq(fentry); + q2 = readq(fentry + 1); + type = FIT_TYPE(q2); + return sprintf(page, "%02x %-25s %x.%02x %016lx %u\n", + type, + fit_type_name(type), + FIT_MAJOR(q2), FIT_MINOR(q2), + q1, + /* mult by sixteen to get size in bytes */ + (unsigned)q2 * 16); +} + +/* We assume that the fit table will be small enough that we can print + * the whole thing into one page. (This is true for our default 16kB + * pages -- each entry is about 60 chars wide when printed.) I read + * somewhere that the maximum size of the FIT is 128 entries, so we're + * OK except for 4kB pages (and no one is going to do that on SN + * anyway). + */ +static int +dump_fit(char *page, unsigned long *fit) +{ + unsigned long qw; + int nentries; + int fentry; + char *p; + + TRACE(); + + DPRINTK("dumping fit from %p\n", (void *)fit); + + qw = readq(fit); + DPRINTK("FIT signature: %016lx (%.8s)\n", qw, (char *)&qw); + if (qw != FIT_SIGNATURE) + printk(KERN_WARNING "Unrecognized FIT signature"); + + qw = readq(fit + 1); + nentries = (unsigned)qw; + DPRINTK("number of fit entries: %u\n", nentries); + /* check that we won't overflow the page -- see comment above */ + BUG_ON(nentries * 60 > PAGE_SIZE); + + p = page; + for (fentry = 0; fentry < nentries; fentry++) + /* each FIT entry is two 64 bit words */ + p += dump_fit_entry(p, fit + 2 * fentry); + + return p - page; +} + +static int +dump_version(char *page, unsigned long *fit) +{ + int nentries; + int fentry; + unsigned long qw; + + TRACE(); + + nentries = (unsigned)readq(fit + 1); + BUG_ON(nentries * 60 > PAGE_SIZE); + + for (fentry = 0; fentry < nentries; fentry++) { + qw = readq(fit + 2 * fentry + 1); + if (FIT_TYPE(qw) == FIT_ENTRY_SAL_A) + return sprintf(page, "%x.%02x\n", + FIT_MAJOR(qw), FIT_MINOR(qw)); + } + return 0; +} + +/* same as in proc_misc.c */ +static int +proc_calc_metrics(char *page, char **start, off_t off, int count, int *eof, + int len) +{ + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int +read_version_entry(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + + MOD_INC_USE_COUNT; + /* data holds the pointer to this node's FIT */ + len = dump_version(page, (unsigned long *)data); + len = proc_calc_metrics(page, start, off, count, eof, len); + MOD_DEC_USE_COUNT; + return len; +} + +static int +read_fit_entry(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + + MOD_INC_USE_COUNT; + /* data holds the pointer to this node's FIT */ + len = dump_fit(page, (unsigned long *)data); + len = proc_calc_metrics(page, start, off, count, eof, len); + MOD_DEC_USE_COUNT; + + return len; +} + +/* this is a fake FIT that's used on the medusa simulator which + * doesn't usually run a complete PROM. + */ +#ifdef CONFIG_IA64_SGI_SN_SIM +static unsigned long fakefit[] = { + /* this is all we need to satisfy the code below */ + FIT_SIGNATURE, + FIT_ENTRY(FIT_ENTRY_FIT_HEADER, 0x02, 0x60, 2), + /* dump something arbitrary for + * /proc/sgi_prominfo/nodeX/version */ + 0xbadbeef00fa3ef17ul, + FIT_ENTRY(FIT_ENTRY_SAL_A, 0, 0x99, 0x100) +}; +#endif + +static unsigned long * +lookup_fit(int nasid) +{ + unsigned long *fitp; + unsigned long fit_paddr; + unsigned long *fit_vaddr; + +#ifdef CONFIG_IA64_SGI_SN_SIM + if (IS_RUNNING_ON_SIMULATOR()) + return fakefit; +#endif + + fitp = (void *)GLOBAL_MMR_ADDR(nasid, LB_PROM_SPACE - 32); + DPRINTK("pointer to fit at %p\n", (void *)fitp); + fit_paddr = readq(fitp); + DPRINTK("fit pointer contains %lx\n", fit_paddr); + /* snag just the node-relative offset */ + fit_paddr &= ~0ul >> (63-35); + /* the pointer to the FIT is relative to IA-64 compatibility + * space. However, the PROM is mapped at a different offset + * in MMR space (both local and global) + */ + fit_paddr += 0x700000000; + fit_vaddr = (void *)GLOBAL_MMR_ADDR(nasid, fit_paddr); + DPRINTK("fit at %p\n", (void *)fit_vaddr); + return fit_vaddr; +} + +/* module entry points */ +int __init prominfo_init(void); +void __exit prominfo_exit(void); + +module_init(prominfo_init); +module_exit(prominfo_exit); + +static struct proc_dir_entry **proc_entries; +static struct proc_dir_entry *sgi_prominfo_entry; + +#define NODE_NAME_LEN 11 + +int __init +prominfo_init(void) +{ + struct proc_dir_entry **entp; + cnodeid_t cnodeid; + nasid_t nasid; + char name[NODE_NAME_LEN]; + + TRACE(); + + DPRINTK("running on cpu %d\n", smp_processor_id()); + DPRINTK("numnodes %d\n", numnodes); + + proc_entries = kmalloc(numnodes * sizeof(struct proc_dir_entry *), + GFP_KERNEL); + + sgi_prominfo_entry = proc_mkdir("sgi_prominfo", NULL); + + for (cnodeid = 0, entp = proc_entries; + cnodeid < numnodes; + cnodeid++, entp++) { + sprintf(name, "node%d", cnodeid); + *entp = proc_mkdir(name, sgi_prominfo_entry); + nasid = cnodeid_to_nasid(cnodeid); + create_proc_read_entry( + "fit", 0, *entp, read_fit_entry, + lookup_fit(nasid)); + create_proc_read_entry( + "version", 0, *entp, read_version_entry, + lookup_fit(nasid)); + } + + return 0; +} + +void __exit +prominfo_exit(void) +{ + struct proc_dir_entry **entp; + unsigned cnodeid; + char name[NODE_NAME_LEN]; + + TRACE(); + + for (cnodeid = 0, entp = proc_entries; + cnodeid < numnodes; + cnodeid++, entp++) { + remove_proc_entry("fit", *entp); + remove_proc_entry("version", *entp); + sprintf(name, "node%d", cnodeid); + remove_proc_entry(name, sgi_prominfo_entry); + } + remove_proc_entry("sgi_prominfo", NULL); + kfree(proc_entries); +} diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c index 1850229970c14..c7116a35e5b14 100644 --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c +++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c @@ -1,7 +1,7 @@ /* * SN2 Platform specific SMP Support * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -79,284 +79,6 @@ wait_piowc(void) return ws; } -#ifdef PTCG_WAR -/* - * The following structure is used to pass params thru smp_call_function - * to other cpus for flushing TLB ranges. - */ -typedef struct { - unsigned long start; - unsigned long end; - unsigned long nbits; - unsigned int rid; - atomic_t unfinished_count; - char fill[96]; -} ptc_params_t; - -#define NUMPTC 512 - -static ptc_params_t ptcParamArray[NUMPTC] __attribute__((__aligned__(128))); - -/* use separate cache lines on ptcParamsNextByCpu to avoid false sharing */ -static ptc_params_t *ptcParamsNextByCpu[NR_CPUS*16] __attribute__((__aligned__(128))); -static volatile ptc_params_t *ptcParamsEmpty __cacheline_aligned; - -/*REFERENCED*/ -static spinlock_t ptcParamsLock __cacheline_aligned = SPIN_LOCK_UNLOCKED; - -static int ptcInit = 0; -#ifdef PTCDEBUG -static int ptcParamsAllBusy = 0; /* debugging/statistics */ -static int ptcCountBacklog = 0; -static int ptcBacklog[NUMPTC+1]; -static char ptcParamsCounts[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); -static char ptcParamsResults[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); -#endif - -/* - * Make smp_send_flush_tlbsmp_send_flush_tlb() a weak reference, - * so that we get a clean compile with the ia64 patch without the - * actual SN1 specific code in arch/ia64/kernel/smp.c. - */ -extern void smp_send_flush_tlb (void) __attribute((weak)); - - -/** - * sn1_ptc_l_range - purge local translation cache - * @start: start of virtual address range - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Purges the range specified from the local processor's translation cache - * (as opposed to the translation registers). Note that more than the specified - * range *may* be cleared from the cache by some processors. - * - * This is probably not good enough, but I don't want to try to make it better - * until I get some statistics on a running system. At a minimum, we should only - * send IPIs to 1 processor in each TLB domain & have it issue a ptc.g on it's - * own FSB. Also, we only have to serialize per FSB, not globally. - * - * More likely, we will have to do some work to reduce the frequency of calls to - * this routine. - */ -static inline void -sn1_ptc_l_range(unsigned long start, unsigned long end, unsigned long nbits) -{ - do { - __asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); - start += (1UL << nbits); - } while (start < end); - ia64_srlz_d(); -} - -/** - * sn1_received_flush_tlb - cpu tlb flush routine - * - * Flushes the TLB of a given processor. - */ -void -sn1_received_flush_tlb(void) -{ - unsigned long start, end, nbits; - unsigned int rid, saved_rid; - int cpu = smp_processor_id(); - int result; - ptc_params_t *ptcParams; - - ptcParams = ptcParamsNextByCpu[cpu*16]; - if (ptcParams == ptcParamsEmpty) - return; - - do { - start = ptcParams->start; - saved_rid = (unsigned int) ia64_get_rr(start); - end = ptcParams->end; - nbits = ptcParams->nbits; - rid = ptcParams->rid; - - if (saved_rid != rid) { - ia64_set_rr(start, (unsigned long)rid); - ia64_srlz_d(); - } - - sn1_ptc_l_range(start, end, nbits); - - if (saved_rid != rid) - ia64_set_rr(start, (unsigned long)saved_rid); - - ia64_srlz_i(); - - result = atomic_dec(&ptcParams->unfinished_count); -#ifdef PTCDEBUG - { - int i = ptcParams-&ptcParamArray[0]; - ptcParamsResults[cpu][i] = (char) result; - ptcParamsCounts[cpu][i]++; - } -#endif /* PTCDEBUG */ - - if (++ptcParams == &ptcParamArray[NUMPTC]) - ptcParams = &ptcParamArray[0]; - - } while (ptcParams != ptcParamsEmpty); - - ptcParamsNextByCpu[cpu*16] = ptcParams; -} - -/** - * sn1_global_tlb_purge - flush a translation cache range on all processors - * @start: start of virtual address range to flush - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Flushes the translation cache of all processors from @start to @end. - */ -void -sn1_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) -{ - ptc_params_t *params; - ptc_params_t *next; - unsigned long irqflags; -#ifdef PTCDEBUG - ptc_params_t *nextnext; - int backlog = 0; -#endif - - if (smp_num_cpus == 1) { - sn1_ptc_l_range(start, end, nbits); - return; - } - - if (in_interrupt()) { - /* - * If at interrupt level and cannot get spinlock, - * then do something useful by flushing own tlbflush queue - * so as to avoid a possible deadlock. - */ - while (!spin_trylock(&ptcParamsLock)) { - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - udelay(10); /* take it easier on the bus */ - } - } else { - spin_lock(&ptcParamsLock); - } - - if (!ptcInit) { - int cpu; - ptcInit = 1; - memset(ptcParamArray, 0, sizeof(ptcParamArray)); - ptcParamsEmpty = &ptcParamArray[0]; - for (cpu=0; cpu<NR_CPUS; cpu++) - ptcParamsNextByCpu[cpu*16] = &ptcParamArray[0]; - -#ifdef PTCDEBUG - memset(ptcBacklog, 0, sizeof(ptcBacklog)); - memset(ptcParamsCounts, 0, sizeof(ptcParamsCounts)); - memset(ptcParamsResults, 0, sizeof(ptcParamsResults)); -#endif /* PTCDEBUG */ - } - - params = (ptc_params_t *) ptcParamsEmpty; - next = (ptc_params_t *) ptcParamsEmpty + 1; - if (next == &ptcParamArray[NUMPTC]) - next = &ptcParamArray[0]; - -#ifdef PTCDEBUG - nextnext = next + 1; - if (nextnext == &ptcParamArray[NUMPTC]) - nextnext = &ptcParamArray[0]; - - if (ptcCountBacklog) { - /* quick count of backlog */ - ptc_params_t *ptr; - - /* check the current pointer to the beginning */ - ptr = params; - while(--ptr >= &ptcParamArray[0]) { - if (atomic_read(&ptr->unfinished_count) == 0) - break; - ++backlog; - } - - if (backlog) { - /* check the end of the array */ - ptr = &ptcParamArray[NUMPTC]; - while (--ptr > params) { - if (atomic_read(&ptr->unfinished_count) == 0) - break; - ++backlog; - } - } - ptcBacklog[backlog]++; - } -#endif /* PTCDEBUG */ - - /* wait for the next entry to clear...should be rare */ - if (atomic_read(&next->unfinished_count) > 0) { -#ifdef PTCDEBUG - ptcParamsAllBusy++; - - if (atomic_read(&nextnext->unfinished_count) == 0) { - if (atomic_read(&next->unfinished_count) > 0) { - panic("\nnonzero next zero nextnext %lx %lx\n", - (long)next, (long)nextnext); - } - } -#endif - - /* it could be this cpu that is behind */ - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - - /* now we know it's not this cpu, so just wait */ - while (atomic_read(&next->unfinished_count) > 0) { - barrier(); - } - } - - params->start = start; - params->end = end; - params->nbits = nbits; - params->rid = (unsigned int) ia64_get_rr(start); - atomic_set(¶ms->unfinished_count, smp_num_cpus); - - /* The atomic_set above can hit memory *after* the update - * to ptcParamsEmpty below, which opens a timing window - * that other cpus can squeeze into! - */ - mb(); - - /* everything is ready to process: - * -- global lock is held - * -- new entry + 1 is free - * -- new entry is set up - * so now: - * -- update the global next pointer - * -- unlock the global lock - * -- send IPI to notify other cpus - * -- process the data ourselves - */ - ptcParamsEmpty = next; - spin_unlock(&ptcParamsLock); - smp_send_flush_tlb(); - - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - - /* - * Since IPIs are polled event (for now), we need to wait til the - * TLB flush has started. - * wait for the flush to complete - */ - while (atomic_read(¶ms->unfinished_count) > 0) - barrier(); -} - -#endif /* PTCG_WAR */ /** @@ -372,18 +94,10 @@ sn1_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbit void sn2_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) { - int cnode, mycnode, nasid; + int cnode, mycnode, nasid, flushed=0; volatile unsigned long *ptc0, *ptc1; unsigned long flags=0, data0, data1; - /* - * Special case 1 cpu & 1 node. Use local purges. - */ -#ifdef PTCG_WAR - sn1_global_tlb_purge(start, end, nbits); - return; -#endif /* PTCG_WAR */ - data0 = (1UL<<SH_PTC_0_A_SHFT) | (nbits<<SH_PTC_0_PS_SHFT) | ((ia64_get_rr(start)>>8)<<SH_PTC_0_RID_SHFT) | @@ -392,18 +106,9 @@ sn2_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbit ptc0 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_0); ptc1 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_1); - mycnode = local_nodeid; - - /* - * For now, we don't want to spin uninterruptibly waiting - * for the lock. Makes hangs hard to debug. - */ - local_irq_save(flags); - while (!spin_trylock(&sn2_global_ptc_lock)) { - local_irq_restore(flags); - udelay(1); - local_irq_save(flags); - } + mycnode = numa_node_id(); + + spin_lock_irqsave(&sn2_global_ptc_lock, flags); do { data1 = start | (1UL<<SH_PTC_1_START_SHFT); @@ -417,11 +122,13 @@ sn2_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbit ptc0 = CHANGE_NASID(nasid, ptc0); ptc1 = CHANGE_NASID(nasid, ptc1); pio_atomic_phys_write_mmrs(ptc0, data0, ptc1, data1); + flushed = 1; } } - if (wait_piowc() & SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_MASK) + if (flushed && (wait_piowc() & SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_MASK)) { sn2_ptc_deadlock_recovery(data0, data1); + } start += (1UL << nbits); @@ -451,7 +158,7 @@ sn2_ptc_deadlock_recovery(unsigned long data0, unsigned long data1) ptc1 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_1); piows = (long*)pda->pio_write_status_addr; - mycnode = local_nodeid; + mycnode = numa_node_id(); for (cnode = 0; cnode < numnodes; cnode++) { if (is_headless_node(cnode) || cnode == mycnode) @@ -482,16 +189,10 @@ sn2_ptc_deadlock_recovery(unsigned long data0, unsigned long data1) void sn_send_IPI_phys(long physid, int vector, int delivery_mode) { - long nasid, slice; - long val; + long nasid, slice, val; + unsigned long flags=0; volatile long *p; -#ifdef BUS_INT_WAR - if (vector != ap_wakeup_vector && delivery_mode == IA64_IPI_DM_INT) { - return; - } -#endif - nasid = cpu_physical_id_to_nasid(physid); slice = cpu_physical_id_to_slice(physid); @@ -503,12 +204,15 @@ sn_send_IPI_phys(long physid, int vector, int delivery_mode) (0x000feeUL<<SH_IPI_INT_BASE_SHFT); mb(); + if (enable_shub_wars_1_1() ) { + spin_lock_irqsave(&sn2_global_ptc_lock, flags); + } pio_phys_write_mmr(p, val); + if (enable_shub_wars_1_1() ) { + wait_piowc(); + spin_unlock_irqrestore(&sn2_global_ptc_lock, flags); + } -#ifndef CONFIG_SHUB_1_0_SPECIFIC - /* doesn't work on shub 1.0 */ - wait_piowc(); -#endif } /** @@ -536,4 +240,3 @@ sn2_send_IPI(int cpuid, int vector, int delivery_mode, int redirect) sn_send_IPI_phys(physid, vector, delivery_mode); } - diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c index 60eefbac4a21e..e7a8987b672d2 100644 --- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c +++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c @@ -31,6 +31,7 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ #include <linux/config.h> +#include <asm/uaccess.h> #ifdef CONFIG_PROC_FS #include <linux/proc_fs.h> @@ -43,7 +44,7 @@ static int partition_id_read_proc(char *page, char **start, off_t off, return sprintf(page, "%d\n", sn_local_partid()); } -struct proc_dir_entry * sgi_proc_dir = NULL; +static struct proc_dir_entry * sgi_proc_dir; void register_sn_partition_id(void) { @@ -135,11 +136,60 @@ register_sn_force_interrupt(void) { entry->write_proc = sn_force_interrupt_write_proc; } } + +extern int sn_linkstats_get(char *); +extern int sn_linkstats_reset(unsigned long); + +static int +sn_linkstats_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) { + + return sn_linkstats_get(page); +} + +static int +sn_linkstats_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char s[64]; + unsigned long msecs; + int e = count; + + if (copy_from_user(s, buffer, count < sizeof(s) ? count : sizeof(s))) + e = -EFAULT; + else { + if (sscanf(s, "%lu", &msecs) != 1 || msecs < 5) + /* at least 5 milliseconds between updates */ + e = -EINVAL; + else + sn_linkstats_reset(msecs); + } + + return e; +} + +void +register_sn_linkstats(void) { + struct proc_dir_entry *entry; + + if (!sgi_proc_dir) { + sgi_proc_dir = proc_mkdir("sgi_sn", 0); + } + entry = create_proc_entry("linkstats", 0444, sgi_proc_dir); + if (entry) { + entry->nlink = 1; + entry->data = 0; + entry->read_proc = sn_linkstats_read_proc; + entry->write_proc = sn_linkstats_write_proc; + } +} + void register_sn_procfs(void) { register_sn_partition_id(); register_sn_serial_numbers(); register_sn_force_interrupt(); + register_sn_linkstats(); } #endif /* CONFIG_PROC_FS */ diff --git a/arch/ia64/sn/kernel/sn_asm.S b/arch/ia64/sn/kernel/sn_asm.S deleted file mode 100644 index 833a399afe96e..0000000000000 --- a/arch/ia64/sn/kernel/sn_asm.S +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include <linux/config.h> -#ifdef CONFIG_IA64_SGI_AUTOTEST - -// Testing only. -// Routine will cause MCAs -// zzzmca(n) -// n=0 MCA via duplicate TLB dropin -// n=1 MCA via read of garbage address -// n=2 MCA via lfetch read of garbage address -// - -#define ITIR(key, ps) ((key<<8) | (ps<<2)) -#define TLB_PAGESIZE 28 // Use 256MB pages for now. - - .global zzzmca - .proc zzzmca -zzzmca: - alloc loc4 = ar.pfs,2,8,1,0;; - cmp.ne p6,p0=r32,r0;; - movl r2=0x2dead - movl r3=0x3dead - movl r15=0x15dead - movl r16=0x16dead - movl r31=0x31dead - movl loc0=0x34beef - movl loc1=0x35beef - movl loc2=0x36beef - movl loc3=0x37beef - movl out0=0x42beef - - movl r20=0x32feed;; - mov ar32=r20 - movl r20=0x36feed;; - mov ar36=r20 - movl r20=0x65feed;; - mov ar65=r20 - movl r20=0x66feed;; - mov ar66=r20 - -(p6) br.cond.sptk 1f - - rsm 0x2000;; - srlz.d; - mov r11 = 5 - mov r3 = ITIR(0,TLB_PAGESIZE);; - mov cr.itir = r3 - mov r10 = 0;; - itr.d dtr[r11] = r10;; - mov r11 = 6 - - itr.d dtr[r11] = r10;; - br 9f - -1: - cmp.eq p6,p7=1,r32 -#ifdef CONFIG_IA64_SGI_SN1 - movl r8=0xe00000fe00000048;; -#else - movl r8=0xe0007fb000000048;; -#endif - (p6) ld8 r9=[r8] - (p7) lfetch.fault.nt2 [r8] - ;; - mf - ;; - mf.a - ;; - srlz.d - -9: mov ar.pfs=loc4 - br.ret.sptk rp - - .endp zzzmca - -#endif diff --git a/arch/ia64/sn/kernel/sn_ksyms.c b/arch/ia64/sn/kernel/sn_ksyms.c index ec882453610d3..97f3cf5208dbe 100644 --- a/arch/ia64/sn/kernel/sn_ksyms.c +++ b/arch/ia64/sn/kernel/sn_ksyms.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -16,11 +16,10 @@ #include <asm/machvec.h> #include <asm/sn/intr.h> -#include <asm/sn/arch.h> #include <linux/mm.h> -#include <linux/devfs_fs_kernel.h> -extern devfs_handle_t base_io_scsi_ctlr_vhdl[]; +#include <asm/sn/sgi.h> +extern vertex_hdl_t base_io_scsi_ctlr_vhdl[]; #include <asm/sn/types.h> extern cnodeid_t master_node_get(devfs_handle_t vhdl); #include <asm/sn/arch.h> @@ -32,9 +31,9 @@ EXPORT_SYMBOL(master_node_get); * symbols referenced by the PCIBA module */ #include <asm/sn/invent.h> -#include <asm/sn/hack.h> #include <asm/sn/hcl.h> #include <asm/sn/pci/pciio.h> +#include <asm/sn/sn_cpuid.h> devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); @@ -55,29 +54,26 @@ EXPORT_SYMBOL(__va_debug); EXPORT_SYMBOL(sn_send_IPI_phys); /* symbols referenced by partitioning modules */ -#include <asm/sn/bte_copy.h> +#include <asm/sn/bte.h> +EXPORT_SYMBOL(bte_copy); EXPORT_SYMBOL(bte_unaligned_copy); #include <asm/sal.h> EXPORT_SYMBOL(ia64_sal); +EXPORT_SYMBOL(physical_node_map); -#ifdef CONFIG_IA64_SGI_SN2 #include <asm/sn/sn_sal.h> EXPORT_SYMBOL(sal_lock); EXPORT_SYMBOL(sn_partid); EXPORT_SYMBOL(sn_local_partid); EXPORT_SYMBOL(sn_system_serial_number_string); EXPORT_SYMBOL(sn_partition_serial_number); -#endif + +EXPORT_SYMBOL(sn_mmiob); /* added by tduffy 04.08.01 to fix depmod issues */ #include <linux/mmzone.h> -#ifdef BUS_INT_WAR -extern void sn_add_polled_interrupt(int, int); -extern void sn_delete_polled_interrupt(int); -EXPORT_SYMBOL(sn_add_polled_interrupt); -EXPORT_SYMBOL(sn_delete_polled_interrupt); -#endif - extern nasid_t master_nasid; EXPORT_SYMBOL(master_nasid); + +EXPORT_SYMBOL(sn_flush_all_caches); diff --git a/arch/ia64/sn/kernel/sv.c b/arch/ia64/sn/kernel/sv.c index 84bedef9f6e28..0fa601f910038 100644 --- a/arch/ia64/sn/kernel/sv.c +++ b/arch/ia64/sn/kernel/sv.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This implemenation of synchronization variables is heavily based on * one done by Steve Lord <lord@sgi.com> |