bte_copy.h
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * This file is subject to the terms and conditions of the GNU General Public
  3.  * License.  See the file "COPYING" in the main directory of this archive
  4.  * for more details.
  5.  * 
  6.  * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All rights reserved.
  7.  */
  8. #ifndef _ASM_IA64_SN_BTE_COPY_H
  9. #define _ASM_IA64_SN_BTE_COPY_H
  10. #ident "$Revision: 1.1 $"
  11. #include <asm/sn/bte.h>
  12. #include <asm/sn/sgi.h>
  13. #include <asm/sn/pda.h>
  14. #include <asm/delay.h>
  15. /*
  16.  * BTE_LOCKING support - Undefining the following line will
  17.  * adapt the bte_copy code to support one bte per cpu in
  18.  * synchronous mode.  Even if bte_copy is called with a
  19.  * notify address, the bte will spin and wait for the transfer
  20.  * to complete.  By defining the following, spin_locks and
  21.  * busy checks are placed around the initiation of a BTE
  22.  * transfer and multiple bte's per cpu are supported.
  23.  */
  24. #define CONFIG_IA64_SGI_BTE_LOCKING 1
  25. /*
  26.  * Some macros to simplify reading.
  27.  *
  28.  * Start with macros to locate the BTE control registers.
  29.  */
  30. #define BTEREG_LNSTAT_ADDR (bte->bte_base_addr)
  31. #define BTEREG_SOURCE_ADDR (bte->bte_base_addr + IIO_IBSA0 - IIO_IBLS0)
  32. #define BTEREG_DEST_ADDR (bte->bte_base_addr + IIO_IBDA0 - IIO_IBLS0)
  33. #define BTEREG_CTRL_ADDR ((volatile char *)bte->bte_base_addr + IIO_IBCT0 - IIO_IBLS0)
  34. #define BTEREG_NOTIF_ADDR (bte->bte_base_addr + IIO_IBNA0 - IIO_IBLS0)
  35. /* Some macros to force the IBCT0 value valid. */
  36. #define BTE_VALID_MODES BTE_NOTIFY
  37. #define BTE_VLD_MODE(x) (x & BTE_VALID_MODES)
  38. // #define DEBUG_BTE
  39. // #define DEBUG_BTE_VERBOSE
  40. // #define DEBUG_TIME_BTE
  41. #ifdef DEBUG_BTE
  42. #  define DPRINTK(x) printk x // Terse
  43. #  ifdef DEBUG_BTE_VERBOSE
  44. #    define DPRINTKV(x) printk x // Verbose
  45. #  else
  46. #    define DPRINTKV(x)
  47. #  endif
  48. #else
  49. #  define DPRINTK(x)
  50. #  define DPRINTKV(x)
  51. #endif
  52. #ifdef DEBUG_TIME_BTE
  53. extern u64 BteSetupTime;
  54. extern u64 BteTransferTime;
  55. extern u64 BteTeardownTime;
  56. extern u64 BteExecuteTime;
  57. #endif
  58. /*
  59.  * bte_copy(src, dest, len, mode, notification)
  60.  *
  61.  * use the block transfer engine to move kernel
  62.  * memory from src to dest using the assigned mode.
  63.  *
  64.  * Paramaters:
  65.  *   src - physical address of the transfer source.
  66.  *   dest - physical address of the transfer destination.
  67.  *   len - number of bytes to transfer from source to dest.
  68.  *   mode - hardware defined.  See reference information
  69.  *          for IBCT0/1 in the SHUB Programmers Reference
  70.  *   notification - kernel virtual address of the notification cache
  71.  *                  line.  If NULL, the default is used and
  72.  *                  the bte_copy is synchronous.
  73.  *
  74.  * NOTE:  This function requires src, dest, and len to
  75.  * be cache line aligned.
  76.  */
  77. extern __inline__ bte_result_t
  78. bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification)
  79. {
  80. #ifdef CONFIG_IA64_SGI_BTE_LOCKING
  81. int bte_to_use;
  82. #endif
  83. #ifdef DEBUG_TIME_BTE
  84. u64 invokeTime = 0;
  85. u64 completeTime = 0;
  86. u64 xferStartTime = 0;
  87. u64 xferCompleteTime = 0;
  88. #endif
  89. u64 transferSize;
  90. bteinfo_t *bte;
  91. #ifdef DEBUG_TIME_BTE
  92. invokeTime = ia64_get_itc();
  93. #endif
  94. DPRINTK(("bte_copy (0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)n",
  95.  src, dest, len, mode, notification));
  96. if (len == 0) {
  97. return (BTE_SUCCESS);
  98. }
  99. ASSERT(!((len & L1_CACHE_MASK) ||
  100.  (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK)));
  101. ASSERT(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT));
  102. #ifdef CONFIG_IA64_SGI_BTE_LOCKING
  103. {
  104. bte_to_use = 0;
  105. /* Attempt to lock one of the BTE interfaces */
  106. while ((*pda.cpubte[bte_to_use]->
  107. mostRecentNotification & IBLS_BUSY)
  108.        &&
  109.        (!(spin_trylock
  110.   (&(pda.cpubte[bte_to_use]->spinlock))))
  111.        && (bte_to_use < BTES_PER_NODE)) {
  112. bte_to_use++;
  113. }
  114. if ((bte_to_use >= BTES_PER_NODE) &&
  115.     !(mode & BTE_WACQUIRE)) {
  116. return (BTEFAIL_NOTAVAIL);
  117. }
  118. /* Wait until a bte is available. */
  119. }
  120. while (bte_to_use >= BTES_PER_NODE);
  121. bte = pda.cpubte[bte_to_use];
  122. DPRINTKV(("Got a lock on bte %dn", bte_to_use));
  123. #else
  124. /* Assuming one BTE per CPU. */
  125. bte = pda.cpubte[0];
  126. #endif
  127. /*
  128.  * The following are removed for optimization but is
  129.  * available in the event that the SHUB exhibits
  130.  * notification problems similar to the hub, bedrock et al.
  131.  *
  132.  * bte->mostRecentSrc = src;
  133.  * bte->mostRecentDest = dest;
  134.  * bte->mostRecentLen = len;
  135.  * bte->mostRecentMode = mode;
  136.  */
  137. if (notification == NULL) {
  138. /* User does not want to be notified. */
  139. bte->mostRecentNotification = &bte->notify;
  140. } else {
  141. bte->mostRecentNotification = notification;
  142. }
  143. /* Calculate the number of cache lines to transfer. */
  144. transferSize = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK);
  145. DPRINTKV(("Calculated transfer size of %d cache linesn",
  146.   transferSize));
  147. /* Initialize the notification to a known value. */
  148. *bte->mostRecentNotification = -1L;
  149. DPRINTKV(("Before, status is 0x%lx and notify is 0x%lxn",
  150.   HUB_L(BTEREG_LNSTAT_ADDR),
  151.   *bte->mostRecentNotification));
  152. /* Set the status reg busy bit and transfer length */
  153. DPRINTKV(("IBLS - HUB_S(0x%lx, 0x%lx)n",
  154.   BTEREG_LNSTAT_ADDR, IBLS_BUSY | transferSize));
  155. HUB_S(BTEREG_LNSTAT_ADDR, IBLS_BUSY | transferSize);
  156. DPRINTKV(("After setting status, status is 0x%lx and notify is 0x%lxn", HUB_L(BTEREG_LNSTAT_ADDR), *bte->mostRecentNotification));
  157. /* Set the source and destination registers */
  158. DPRINTKV(("IBSA - HUB_S(0x%lx, 0x%lx)n", BTEREG_SOURCE_ADDR,
  159.   src));
  160. HUB_S(BTEREG_SOURCE_ADDR, src);
  161. DPRINTKV(("IBDA - HUB_S(0x%lx, 0x%lx)n", BTEREG_DEST_ADDR, dest));
  162. HUB_S(BTEREG_DEST_ADDR, dest);
  163. /* Set the notification register */
  164. DPRINTKV(("IBNA - HUB_S(0x%lx, 0x%lx)n", BTEREG_NOTIF_ADDR,
  165.   __pa(bte->mostRecentNotification)));
  166. HUB_S(BTEREG_NOTIF_ADDR, (__pa(bte->mostRecentNotification)));
  167. DPRINTKV(("Set Notify, status is 0x%lx and notify is 0x%lxn",
  168.   HUB_L(BTEREG_LNSTAT_ADDR),
  169.   *bte->mostRecentNotification));
  170. /* Initiate the transfer */
  171. DPRINTKV(("IBCT - HUB_S(0x%lx, 0x%lx)n", BTEREG_CTRL_ADDR, mode));
  172. #ifdef DEBUG_TIME_BTE
  173. xferStartTime = ia64_get_itc();
  174. #endif
  175. HUB_S(BTEREG_CTRL_ADDR, BTE_VLD_MODE(mode));
  176. DPRINTKV(("Initiated, status is 0x%lx and notify is 0x%lxn",
  177.   HUB_L(BTEREG_LNSTAT_ADDR),
  178.   *bte->mostRecentNotification));
  179. // >>> Temporarily work around not getting a notification
  180. // from medusa.
  181. // *bte->mostRecentNotification = HUB_L(bte->bte_base_addr);
  182. if (notification == NULL) {
  183. /*
  184.  * Calculate our timeout
  185.  *
  186.  * What are we doing here?  We are trying to determine
  187.  * the fastest time the BTE could have transfered our
  188.  * block of data.  By takine the clock frequency (ticks/sec)
  189.  * divided by the BTE MaxT Transfer Rate (lines/sec)
  190.  * times the transfer size (lines), we get a tick
  191.  * offset from current time that the transfer should
  192.  * complete.
  193.  *
  194.  * Why do this?  We are watching for a notification
  195.  * failure from the BTE.  This behaviour has been
  196.  * seen in the SN0 and SN1 hardware on rare circumstances
  197.  * and is expected in SN2.  By checking at the
  198.  * ideal transfer timeout, we minimize our time
  199.  * delay from hardware completing our request and
  200.  * our detecting the failure.
  201.  */
  202. bte->idealTransferTimeout = jiffies +
  203.     (HZ / BTE_MAXT_LINES_PER_SECOND * transferSize);
  204. while ((IBLS_BUSY & bte->notify)) {
  205. /*
  206.  * Notification Workaround: When the max
  207.  * theoretical time has elapsed, read the hub
  208.  * status register into the notification area.
  209.  * This fakes the shub performing the copy.
  210.  */
  211. if (jiffies > bte->idealTransferTimeout) {
  212. bte->notify = HUB_L(bte->bte_base_addr);
  213. bte->idealTransferTimeoutReached++;
  214. bte->idealTransferTimeout = jiffies +
  215.     (HZ / BTE_MAXT_LINES_PER_SECOND *
  216.      (bte->notify & BTE_LEN_MASK));
  217. }
  218. }
  219. #ifdef DEBUG_TIME_BTE
  220. xferCompleteTime = ia64_get_itc();
  221. #endif
  222. if (bte->notify & IBLS_ERROR) {
  223. /* >>> Need to do real error checking. */
  224. transferSize = 0;
  225. #ifdef CONFIG_IA64_SGI_BTE_LOCKING
  226. spin_unlock(&(bte->spinlock));
  227. #endif
  228. return (BTEFAIL_ERROR);
  229. }
  230. }
  231. #ifdef CONFIG_IA64_SGI_BTE_LOCKING
  232. spin_unlock(&(bte->spinlock));
  233. #endif
  234. #ifdef DEBUG_TIME_BTE
  235. completeTime = ia64_get_itc();
  236. BteSetupTime = xferStartTime - invokeTime;
  237. BteTransferTime = xferCompleteTime - xferStartTime;
  238. BteTeardownTime = completeTime - xferCompleteTime;
  239. BteExecuteTime = completeTime - invokeTime;
  240. #endif
  241. return (BTE_SUCCESS);
  242. }
  243. /*
  244.  * Define the bte_unaligned_copy as an extern.
  245.  */
  246. extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64, char *);
  247. /*
  248.  * The following is the prefered way of calling bte_unaligned_copy
  249.  * If the copy is fully cache line aligned, then bte_copy is
  250.  * used instead.  Since bte_copy is inlined, this saves a call
  251.  * stack.  NOTE: bte_copy is called synchronously and does block
  252.  * until the transfer is complete.  In order to get the asynch
  253.  * version of bte_copy, you must perform this check yourself.
  254.  */
  255. #define BTE_UNALIGNED_COPY(src, dest, len, mode, bteBlock) 
  256. if ((len & L1_CACHE_MASK) || 
  257.     (src & L1_CACHE_MASK) || 
  258.     (dest & L1_CACHE_MASK)) { 
  259. bte_unaligned_copy (src, dest, len, mode, bteBlock); 
  260. } else { 
  261. bte_copy(src, dest, len, mode, NULL); 
  262. }
  263. #endif /* _ASM_IA64_SN_BTE_COPY_H */