⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bte_copy.h

📁 该文件是rt_linux
💻 H
字号:
/* * 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. */#ifndef _ASM_IA64_SN_BTE_COPY_H#define _ASM_IA64_SN_BTE_COPY_H#ident "$Revision: 1.1 $"#include <asm/sn/bte.h>#include <asm/sn/sgi.h>#include <asm/sn/pda.h>#include <asm/delay.h>/* * BTE_LOCKING support - Undefining the following line will * adapt the bte_copy code to support one bte per cpu in * synchronous mode.  Even if bte_copy is called with a * notify address, the bte will spin and wait for the transfer * to complete.  By defining the following, spin_locks and * busy checks are placed around the initiation of a BTE * transfer and multiple bte's per cpu are supported. */#define CONFIG_IA64_SGI_BTE_LOCKING 1/* * Some macros to simplify reading. * * Start with macros to locate the BTE control registers. */#define BTEREG_LNSTAT_ADDR (bte->bte_base_addr)#define BTEREG_SOURCE_ADDR (bte->bte_base_addr + IIO_IBSA0 - IIO_IBLS0)#define BTEREG_DEST_ADDR (bte->bte_base_addr + IIO_IBDA0 - IIO_IBLS0)#define BTEREG_CTRL_ADDR ((volatile char *)bte->bte_base_addr + IIO_IBCT0 - IIO_IBLS0)#define BTEREG_NOTIF_ADDR (bte->bte_base_addr + IIO_IBNA0 - IIO_IBLS0)/* Some macros to force the IBCT0 value valid. */#define BTE_VALID_MODES BTE_NOTIFY#define BTE_VLD_MODE(x) (x & BTE_VALID_MODES)// #define DEBUG_BTE// #define DEBUG_BTE_VERBOSE// #define DEBUG_TIME_BTE#ifdef DEBUG_BTE#  define DPRINTK(x) printk x	// Terse#  ifdef DEBUG_BTE_VERBOSE#    define DPRINTKV(x) printk x	// Verbose#  else#    define DPRINTKV(x)#  endif#else#  define DPRINTK(x)#  define DPRINTKV(x)#endif#ifdef DEBUG_TIME_BTEextern u64 BteSetupTime;extern u64 BteTransferTime;extern u64 BteTeardownTime;extern u64 BteExecuteTime;#endif/* * 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:  This function requires src, dest, and len to * be cache line aligned. */extern __inline__ bte_result_tbte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification){#ifdef CONFIG_IA64_SGI_BTE_LOCKING	int bte_to_use;#endif#ifdef DEBUG_TIME_BTE	u64 invokeTime = 0;	u64 completeTime = 0;	u64 xferStartTime = 0;	u64 xferCompleteTime = 0;#endif	u64 transferSize;	bteinfo_t *bte;#ifdef DEBUG_TIME_BTE	invokeTime = ia64_get_itc();#endif	DPRINTK(("bte_copy (0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",		 src, dest, len, mode, notification));	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));#ifdef CONFIG_IA64_SGI_BTE_LOCKING	{		bte_to_use = 0;		/* Attempt to lock one of the BTE interfaces */		while ((*pda.cpubte[bte_to_use]->			mostRecentNotification & IBLS_BUSY)		       &&		       (!(spin_trylock			  (&(pda.cpubte[bte_to_use]->spinlock))))		       && (bte_to_use < BTES_PER_NODE)) {			bte_to_use++;		}		if ((bte_to_use >= BTES_PER_NODE) &&		    !(mode & BTE_WACQUIRE)) {			return (BTEFAIL_NOTAVAIL);		}		/* Wait until a bte is available. */	}	while (bte_to_use >= BTES_PER_NODE);	bte = pda.cpubte[bte_to_use];	DPRINTKV(("Got a lock on bte %d\n", bte_to_use));#else	/* Assuming one BTE per CPU. */	bte = pda.cpubte[0];#endif	/*	 * The following are removed for optimization but is	 * available in the event that the SHUB exhibits	 * notification problems similar to the hub, bedrock et al.	 *	 * bte->mostRecentSrc = src;	 * bte->mostRecentDest = dest;	 * bte->mostRecentLen = len;	 * bte->mostRecentMode = mode;	 */	if (notification == NULL) {		/* User does not want to be notified. */		bte->mostRecentNotification = &bte->notify;	} else {		bte->mostRecentNotification = notification;	}	/* Calculate the number of cache lines to transfer. */	transferSize = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK);	DPRINTKV(("Calculated transfer size of %d cache lines\n",		  transferSize));	/* Initialize the notification to a known value. */	*bte->mostRecentNotification = -1L;	DPRINTKV(("Before, status is 0x%lx and notify is 0x%lx\n",		  HUB_L(BTEREG_LNSTAT_ADDR),		  *bte->mostRecentNotification));	/* Set the status reg busy bit and transfer length */	DPRINTKV(("IBLS - HUB_S(0x%lx, 0x%lx)\n",		  BTEREG_LNSTAT_ADDR, IBLS_BUSY | transferSize));	HUB_S(BTEREG_LNSTAT_ADDR, IBLS_BUSY | transferSize);	DPRINTKV(("After setting status, status is 0x%lx and notify is 0x%lx\n", HUB_L(BTEREG_LNSTAT_ADDR), *bte->mostRecentNotification));	/* Set the source and destination registers */	DPRINTKV(("IBSA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_SOURCE_ADDR,		  src));	HUB_S(BTEREG_SOURCE_ADDR, src);	DPRINTKV(("IBDA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_DEST_ADDR, dest));	HUB_S(BTEREG_DEST_ADDR, dest);	/* Set the notification register */	DPRINTKV(("IBNA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_NOTIF_ADDR,		  __pa(bte->mostRecentNotification)));	HUB_S(BTEREG_NOTIF_ADDR, (__pa(bte->mostRecentNotification)));	DPRINTKV(("Set Notify, status is 0x%lx and notify is 0x%lx\n",		  HUB_L(BTEREG_LNSTAT_ADDR),		  *bte->mostRecentNotification));	/* Initiate the transfer */	DPRINTKV(("IBCT - HUB_S(0x%lx, 0x%lx)\n", BTEREG_CTRL_ADDR, mode));#ifdef DEBUG_TIME_BTE	xferStartTime = ia64_get_itc();#endif	HUB_S(BTEREG_CTRL_ADDR, BTE_VLD_MODE(mode));	DPRINTKV(("Initiated, status is 0x%lx and notify is 0x%lx\n",		  HUB_L(BTEREG_LNSTAT_ADDR),		  *bte->mostRecentNotification));	// >>> Temporarily work around not getting a notification	// from medusa.	// *bte->mostRecentNotification = HUB_L(bte->bte_base_addr);	if (notification == NULL) {		/*		 * Calculate our timeout		 *		 * What are we doing here?  We are trying to determine		 * the fastest time the BTE could have transfered our		 * block of data.  By takine the clock frequency (ticks/sec)		 * divided by the BTE MaxT Transfer Rate (lines/sec)		 * times the transfer size (lines), we get a tick		 * offset from current time that the transfer should		 * complete.		 *		 * Why do this?  We are watching for a notification		 * failure from the BTE.  This behaviour has been		 * seen in the SN0 and SN1 hardware on rare circumstances		 * and is expected in SN2.  By checking at the		 * ideal transfer timeout, we minimize our time		 * delay from hardware completing our request and		 * our detecting the failure.		 */		bte->idealTransferTimeout = jiffies +		    (HZ / BTE_MAXT_LINES_PER_SECOND * transferSize);		while ((IBLS_BUSY & bte->notify)) {			/*			 * Notification Workaround: When the max			 * theoretical time has elapsed, read the hub			 * status register into the notification area.			 * This fakes the shub performing the copy.			 */			if (jiffies > bte->idealTransferTimeout) {				bte->notify = HUB_L(bte->bte_base_addr);				bte->idealTransferTimeoutReached++;				bte->idealTransferTimeout = jiffies +				    (HZ / BTE_MAXT_LINES_PER_SECOND *				     (bte->notify & BTE_LEN_MASK));			}		}#ifdef DEBUG_TIME_BTE		xferCompleteTime = ia64_get_itc();#endif		if (bte->notify & IBLS_ERROR) {			/* >>> Need to do real error checking. */			transferSize = 0;#ifdef CONFIG_IA64_SGI_BTE_LOCKING			spin_unlock(&(bte->spinlock));#endif			return (BTEFAIL_ERROR);		}	}#ifdef CONFIG_IA64_SGI_BTE_LOCKING	spin_unlock(&(bte->spinlock));#endif#ifdef DEBUG_TIME_BTE	completeTime = ia64_get_itc();	BteSetupTime = xferStartTime - invokeTime;	BteTransferTime = xferCompleteTime - xferStartTime;	BteTeardownTime = completeTime - xferCompleteTime;	BteExecuteTime = completeTime - invokeTime;#endif	return (BTE_SUCCESS);}/* * Define the bte_unaligned_copy as an extern. */extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64, char *);/* * The following is the prefered way of calling bte_unaligned_copy * If the copy is fully cache line aligned, then bte_copy is * used instead.  Since bte_copy is inlined, this saves a call * stack.  NOTE: bte_copy is called synchronously and does block * until the transfer is complete.  In order to get the asynch * version of bte_copy, you must perform this check yourself. */#define BTE_UNALIGNED_COPY(src, dest, len, mode, bteBlock) \	if ((len & L1_CACHE_MASK) || \	    (src & L1_CACHE_MASK) || \	    (dest & L1_CACHE_MASK)) { \		bte_unaligned_copy (src, dest, len, mode, bteBlock); \	} else { \		bte_copy(src, dest, len, mode, NULL); \	}#endif				/* _ASM_IA64_SN_BTE_COPY_H */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -