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

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. #include <asm/sn/nodepda.h>
  9. #include <asm/sn/addrs.h>
  10. #include <asm/sn/arch.h>
  11. #include <asm/sn/sn_cpuid.h>
  12. #include <asm/sn/pda.h>
  13. #include <asm/nodedata.h>
  14. #include <linux/bootmem.h>
  15. #include <linux/string.h>
  16. #include <linux/sched.h>
  17. #include <asm/sn/bte_copy.h>
  18. int bte_offsets[] = { IIO_IBLS0, IIO_IBLS1 };
  19. /*
  20.  * bte_init_node(nodepda, cnode, cmdline_p)
  21.  *
  22.  * Initialize the nodepda structure with BTE base addresses and
  23.  * spinlocks.
  24.  *
  25.  */
  26. void
  27. bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode, char **cmdline_p)
  28. {
  29. int bteTestMode = 0;
  30. int cmdoffset = 0;
  31. int i;
  32. #ifdef ZZZ
  33. if (!cmdoffset) {
  34. for (;cmdline_p[cmdoffset]; cmdoffset++) {
  35. if (strstr(cmdline_p[cmdoffset], "btetest")) {
  36. bteTestMode = 1;
  37. break;
  38. }
  39. }
  40. }
  41. #endif
  42. /*
  43.  * Indicate that all the block transfer engines on this node
  44.  * are available.
  45.  */
  46. for (i = 0; i < BTES_PER_NODE; i++) {
  47. #ifdef CONFIG_IA64_SGI_SN2
  48. /* >>> Don't know why the 0x1800000L is here.  Robin */
  49. mynodepda->node_bte_info[i].bte_base_addr =
  50.     (char *)LOCAL_MMR_ADDR(bte_offsets[i] | 0x1800000L);
  51. #elif CONFIG_IA64_SGI_SN1
  52. mynodepda->node_bte_info[i].bte_base_addr =
  53.     (char *)LOCAL_HUB_ADDR(bte_offsets[i]);
  54. #else
  55. #error BTE Not defined for this hardware platform.
  56. #endif
  57. #ifdef CONFIG_IA64_SGI_BTE_LOCKING
  58. /* Initialize the notification and spinlock */
  59. /* so the first transfer can occur. */
  60. mynodepda->node_bte_info[i].mostRecentNotification =
  61.     &(mynodepda->node_bte_info[i].notify);
  62. mynodepda->node_bte_info[i].notify = 0L;
  63. spin_lock_init(&mynodepda->node_bte_info[i].spinlock);
  64. #endif /* CONFIG_IA64_SGI_BTE_LOCKING */
  65. if (bteTestMode) {
  66. mynodepda->node_bte_info[i].bteTestBuf =
  67. alloc_bootmem_node(NODE_DATA(cnode),
  68.    BTE_MAX_XFER);
  69. }
  70. }
  71. }
  72. /*
  73.  * bte_init_cpu()
  74.  *
  75.  * Initialize the cpupda structure with pointers to the
  76.  * nodepda bte blocks.
  77.  *
  78.  */
  79. void
  80. bte_init_cpu(void)
  81. {
  82. /* Called by setup.c as each cpu is being added to the nodepda */
  83. if (local_node_data->active_cpu_count & 0x1) {
  84. pda.cpubte[0] = &(nodepda->node_bte_info[0]);
  85. pda.cpubte[1] = &(nodepda->node_bte_info[1]);
  86. } else {
  87. pda.cpubte[0] = &(nodepda->node_bte_info[1]);
  88. pda.cpubte[1] = &(nodepda->node_bte_info[0]);
  89. }
  90. }
  91. /*
  92.  * bte_unaligned_copy(src, dest, len, mode)
  93.  *
  94.  * use the block transfer engine to move kernel
  95.  * memory from src to dest using the assigned mode.
  96.  *
  97.  * Paramaters:
  98.  *   src - physical address of the transfer source.
  99.  *   dest - physical address of the transfer destination.
  100.  *   len - number of bytes to transfer from source to dest.
  101.  *   mode - hardware defined.  See reference information
  102.  *          for IBCT0/1 in the SGI documentation.
  103.  *   bteBlock - kernel virtual address of a temporary
  104.  *              buffer used during unaligned transfers.
  105.  *
  106.  * NOTE: If the source, dest, and len are all cache line aligned,
  107.  * then it would be _FAR_ preferrable to use bte_copy instead.
  108.  */
  109. bte_result_t
  110. bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode, char *bteBlock)
  111. {
  112. int destFirstCacheOffset;
  113. u64 headBteSource;
  114. u64 headBteLen;
  115. u64 headBcopySrcOffset;
  116. u64 headBcopyDest;
  117. u64 headBcopyLen;
  118. u64 footBteSource;
  119. u64 footBteLen;
  120. u64 footBcopyDest;
  121. u64 footBcopyLen;
  122. bte_result_t rv;
  123. if (len == 0) {
  124. return (BTE_SUCCESS);
  125. }
  126. headBcopySrcOffset = src & L1_CACHE_MASK;
  127. destFirstCacheOffset = dest & L1_CACHE_MASK;
  128. /*
  129.  * At this point, the transfer is broken into
  130.  * (up to) three sections.  The first section is
  131.  * from the start address to the first physical
  132.  * cache line, the second is from the first physical
  133.  * cache line to the last complete cache line,
  134.  * and the third is from the last cache line to the
  135.  * end of the buffer.  The first and third sections
  136.  * are handled by bte copying into a temporary buffer
  137.  * and then bcopy'ing the necessary section into the
  138.  * final location.  The middle section is handled with
  139.  * a standard bte copy.
  140.  *
  141.  * One nasty exception to the above rule is when the
  142.  * source and destination are not symetrically
  143.  * mis-aligned.  If the source offset from the first
  144.  * cache line is different from the destination offset,
  145.  * we make the first section be the entire transfer
  146.  * and the bcopy the entire block into place.
  147.  */
  148. if (headBcopySrcOffset == destFirstCacheOffset) {
  149. /*
  150.  * Both the source and destination are the same
  151.  * distance from a cache line boundary so we can
  152.  * use the bte to transfer the bulk of the
  153.  * data.
  154.  */
  155. headBteSource = src & ~L1_CACHE_MASK;
  156. headBcopyDest = dest;
  157. if (headBcopySrcOffset) {
  158. headBcopyLen =
  159.     (len >
  160.      (L1_CACHE_BYTES -
  161.       headBcopySrcOffset) ? L1_CACHE_BYTES
  162.      - headBcopySrcOffset : len);
  163. headBteLen = L1_CACHE_BYTES;
  164. } else {
  165. headBcopyLen = 0;
  166. headBteLen = 0;
  167. }
  168. if (len > headBcopyLen) {
  169. footBcopyLen =
  170.     (len - headBcopyLen) & L1_CACHE_MASK;
  171. footBteLen = L1_CACHE_BYTES;
  172. footBteSource = src + len - footBcopyLen;
  173. footBcopyDest = dest + len - footBcopyLen;
  174. if (footBcopyDest ==
  175.     (headBcopyDest + headBcopyLen)) {
  176. /*
  177.  * We have two contigous bcopy
  178.  * blocks.  Merge them.
  179.  */
  180. headBcopyLen += footBcopyLen;
  181. headBteLen += footBteLen;
  182. } else if (footBcopyLen > 0) {
  183. rv = bte_copy(footBteSource,
  184.       __pa(bteBlock),
  185.       footBteLen, mode, NULL);
  186. if (rv != BTE_SUCCESS) {
  187. return (rv);
  188. }
  189. memcpy(__va(footBcopyDest),
  190.        (char *)bteBlock, footBcopyLen);
  191. }
  192. } else {
  193. footBcopyLen = 0;
  194. footBteLen = 0;
  195. }
  196. if (len > (headBcopyLen + footBcopyLen)) {
  197. /* now transfer the middle. */
  198. rv = bte_copy((src + headBcopyLen),
  199.       (dest +
  200.        headBcopyLen),
  201.       (len - headBcopyLen -
  202.        footBcopyLen), mode, NULL);
  203. if (rv != BTE_SUCCESS) {
  204. return (rv);
  205. }
  206. }
  207. } else {
  208. /*
  209.  * The transfer is not symetric, we will
  210.  * allocate a buffer large enough for all the
  211.  * data, bte_copy into that buffer and then
  212.  * bcopy to the destination.
  213.  */
  214. /* Add the leader from source */
  215. headBteLen = len + (src & L1_CACHE_MASK);
  216. /* Add the trailing bytes from footer. */
  217. headBteLen +=
  218.     L1_CACHE_BYTES - (headBteLen & L1_CACHE_MASK);
  219. headBteSource = src & ~L1_CACHE_MASK;
  220. headBcopySrcOffset = src & L1_CACHE_MASK;
  221. headBcopyDest = dest;
  222. headBcopyLen = len;
  223. }
  224. if (headBcopyLen > 0) {
  225. rv = bte_copy(headBteSource,
  226.       __pa(bteBlock), headBteLen, mode, NULL);
  227. if (rv != BTE_SUCCESS) {
  228. return (rv);
  229. }
  230. memcpy(__va(headBcopyDest), ((char *)bteBlock +
  231.      headBcopySrcOffset),
  232.        headBcopyLen);
  233. }
  234. return (BTE_SUCCESS);
  235. }