diff options
Diffstat (limited to 'arch/ia64/sn/kernel/bte.c')
-rw-r--r-- | arch/ia64/sn/kernel/bte.c | 321 |
1 files changed, 216 insertions, 105 deletions
diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c index 0e592be762ea70..88409fcc4b8cdc 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]); + } } |