aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/sn/kernel/bte.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/sn/kernel/bte.c')
-rw-r--r--arch/ia64/sn/kernel/bte.c321
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]);
+ }
}