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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* 
  2.  * File...........: linux/drivers/s390/ccwcache.c
  3.  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  4.  *                  Martin Schiwdefsky <schwidefsky@de.ibm.com>
  5.  * Bugreports.to..: <Linux390@de.ibm.com>
  6.  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
  7.  
  8.  * History of changes
  9.  * 11/14/00 redesign by Martin Schwidefsky
  10.  */
  11. #include <linux/module.h>
  12. #include <linux/slab.h>
  13. #include <linux/version.h>
  14. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
  15. #include <linux/spinlock.h>
  16. #else
  17. #include <asm/spinlock.h>
  18. #endif
  19. #include <asm/debug.h>
  20. #include <asm/ccwcache.h>
  21. #include <asm/ebcdic.h>
  22. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
  23. #define CCW_CACHE_SLAB_TYPE (SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA)
  24. #define CCW_CACHE_TYPE (GFP_ATOMIC | GFP_DMA)
  25. #else
  26. #define CCW_CACHE_SLAB_TYPE (SLAB_HWCACHE_ALIGN)
  27. #define CCW_CACHE_TYPE (GFP_ATOMIC)
  28. #define kmem_cache_destroy(x) do {} while(0)
  29. #endif
  30. #undef PRINTK_HEADER
  31. #define PRINTK_HEADER "ccwcache"
  32. /* pointer to list of allocated requests */
  33. static ccw_req_t *ccwreq_actual = NULL;
  34. static spinlock_t ccwchain_lock;
  35. /* pointer to debug area */
  36. static debug_info_t *debug_area = NULL;
  37. /* SECTION: Handling of the dynamically allocated kmem slabs */
  38. /* a name template for the cache-names */
  39. static char ccw_name_template[] = "ccwcache-"; /* fill name with zeroes! */
  40. /* the cache's names */
  41. static char ccw_cache_name[CCW_NUMBER_CACHES][sizeof(ccw_name_template)+1]; 
  42. /* the caches itself*/
  43. static kmem_cache_t *ccw_cache[CCW_NUMBER_CACHES]; 
  44. /* SECTION: (de)allocation of ccw_req_t */
  45. /* 
  46.  * void enchain ( ccw_req_t *request )
  47.  * enchains the request to the ringbuffer
  48.  */
  49. static inline void 
  50. enchain ( ccw_req_t *request )
  51. {
  52. unsigned long flags;
  53. /* Sanity checks */
  54. if ( request == NULL )
  55. BUG();
  56. spin_lock_irqsave(&ccwchain_lock,flags);
  57. if ( ccwreq_actual == NULL ) { /* queue empty */
  58. ccwreq_actual = request;
  59. request->int_prev = ccwreq_actual;
  60. request->int_next = ccwreq_actual;
  61. } else {
  62. request->int_next = ccwreq_actual;
  63. request->int_prev = ccwreq_actual->int_prev;
  64. request->int_prev->int_next = request;
  65. request->int_next->int_prev = request;
  66. }
  67. spin_unlock_irqrestore(&ccwchain_lock,flags);
  68. }
  69. /* 
  70.  * void dechain ( ccw_req_t *request )
  71.  * dechains the request from the ringbuffer
  72.  */
  73. static inline void 
  74. dechain ( ccw_req_t *request )
  75. {
  76. unsigned long flags;
  77. /* Sanity checks */
  78. if ( request == NULL || 
  79.      request->int_next == NULL ||
  80.      request->int_prev == NULL)
  81. BUG();
  82. /* first deallocate request from list of allocates requests */
  83. spin_lock_irqsave(&ccwchain_lock,flags);
  84. if ( request -> int_next == request -> int_prev ) {
  85. ccwreq_actual = NULL;
  86. } else {
  87. if ( ccwreq_actual == request ) {
  88. ccwreq_actual = request->int_next;
  89. }
  90. request->int_prev->int_next = request->int_next;
  91. request->int_next->int_prev = request->int_prev;
  92. }
  93. spin_unlock_irqrestore(&ccwchain_lock,flags);
  94. }
  95. /* 
  96.  * ccw_req_t *ccw_alloc_request ( int cplength, int datasize )
  97.  * allocates a ccw_req_t, that 
  98.  * - can hold a CP of cplength CCWS
  99.  * - can hold additional data up to datasize 
  100.  */
  101. ccw_req_t *
  102. ccw_alloc_request ( char *magic, int cplength, int datasize )
  103. {
  104. ccw_req_t * request = NULL;
  105.         int size_needed;
  106. int data_offset, ccw_offset;
  107. int cachind;
  108. /* Sanity checks */
  109. if ( magic == NULL || datasize > PAGE_SIZE ||
  110.      cplength == 0 || (cplength*sizeof(ccw1_t)) > PAGE_SIZE)
  111. BUG();
  112. debug_text_event ( debug_area, 1, "ALLC");
  113. debug_text_event ( debug_area, 1, magic);
  114. debug_int_event ( debug_area, 1, cplength);
  115. debug_int_event ( debug_area, 1, datasize);
  116. /* We try to keep things together in memory */
  117. size_needed = (sizeof (ccw_req_t) + 7) & -8;
  118. data_offset = ccw_offset = 0;
  119. if (size_needed + datasize <= PAGE_SIZE) {
  120. /* Keep data with the request */
  121. data_offset = size_needed;
  122. size_needed += (datasize + 7) & -8;
  123. }
  124. if (size_needed + cplength*sizeof(ccw1_t) <= PAGE_SIZE) {
  125. /* Keep CCWs with request */
  126. ccw_offset = size_needed;
  127. size_needed += cplength*sizeof(ccw1_t);
  128. }
  129. /* determine cache index for the requested size */
  130. for (cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ )
  131.    if ( size_needed < (SMALLEST_SLAB << cachind) ) 
  132. break;
  133. /* Try to fulfill the request from a cache */
  134. if ( ccw_cache[cachind] == NULL )
  135. BUG();
  136. request = kmem_cache_alloc ( ccw_cache[cachind], CCW_CACHE_TYPE );
  137. if (request == NULL)
  138. return NULL;
  139. memset ( request, 0, (SMALLEST_SLAB << cachind));
  140. request->cache = ccw_cache[cachind];
  141. /* Allocate memory for the extra data */
  142. if (data_offset == 0) {
  143. /* Allocated memory for extra data with kmalloc */
  144.     request->data = (void *) kmalloc(datasize, CCW_CACHE_TYPE );
  145. if (request->data == NULL) {
  146. printk(KERN_WARNING PRINTK_HEADER 
  147.        "Couldn't allocate data arean");
  148. kmem_cache_free(request->cache, request);
  149. return NULL;
  150. }
  151. } else
  152. /* Extra data already allocated with the request */
  153. request->data = (void *) ((addr_t) request + data_offset);
  154. /* Allocate memory for the channel program */
  155. if (ccw_offset == 0) {
  156. /* Allocated memory for the channel program with kmalloc */
  157. request->cpaddr = (ccw1_t *) kmalloc(cplength*sizeof(ccw1_t),
  158.      CCW_CACHE_TYPE);
  159. if (request->cpaddr == NULL) {
  160. printk (KERN_DEBUG PRINTK_HEADER
  161. "Couldn't allocate ccw arean");
  162. if (data_offset == 0)
  163. kfree(request->data);
  164. kmem_cache_free(request->cache, request);
  165. return NULL;
  166. }
  167. } else
  168. /* Channel program already allocated with the request */
  169. request->cpaddr = (ccw1_t *) ((addr_t) request + ccw_offset);
  170. memset ( request->data, 0, datasize );
  171. memset ( request->cpaddr, 0, cplength*sizeof(ccw1_t) );
  172. strncpy ( (char *)(&request->magic), magic, 4);
  173. ASCEBC((char *)(&request->magic),4);
  174. request -> cplength = cplength;
  175. request -> datasize = datasize;
  176. /* enqueue request to list of allocated requests */
  177. enchain(request);
  178. debug_int_event ( debug_area, 1, (long)request);
  179. return request;
  180. }
  181. /* 
  182.  * void ccw_free_request ( ccw_req_t * )
  183.  * deallocates the ccw_req_t, given as argument
  184.  */
  185. void
  186. ccw_free_request ( ccw_req_t * request )
  187. {
  188.         int size_needed;
  189. debug_text_event ( debug_area, 1, "FREE");
  190. debug_int_event ( debug_area, 1, (long)request);
  191. /* Sanity checks */
  192. if ( request == NULL || request->cache == NULL)
  193.                 BUG();
  194.         dechain ( request);
  195. /* Free memory allocated with kmalloc
  196.          * make the same decisions as in ccw_alloc_requets */
  197. size_needed = (sizeof (ccw_req_t) + 7) & -8;
  198. if (size_needed + request->datasize <= PAGE_SIZE)
  199. /* We kept the data with the request */
  200. size_needed += (request->datasize + 7) & -8;
  201. else
  202. kfree(request->data);
  203. if (size_needed + request->cplength*sizeof(ccw1_t) > PAGE_SIZE)
  204. /* We kept the CCWs with request */
  205.                 kfree(request->cpaddr);
  206.         kmem_cache_free(request -> cache, request);
  207. }
  208. /* SECTION: initialization and cleanup functions */
  209. /* 
  210.  * ccwcache_init
  211.  * called as an initializer function for the ccw memory management
  212.  */
  213. int
  214. ccwcache_init (void)
  215. {
  216. int rc = 0;
  217. int cachind;
  218.         /* initialize variables */
  219. spin_lock_init(&ccwchain_lock);
  220. /* allocate a debug area */
  221. debug_area = debug_register( "ccwcache", 2, 4,sizeof(void*));
  222. if ( debug_area == NULL )
  223.                 BUG();
  224.         debug_register_view(debug_area,&debug_hex_ascii_view);
  225.         debug_register_view(debug_area,&debug_raw_view);
  226. debug_text_event ( debug_area, 0, "INIT");
  227. /* First allocate the kmem caches */
  228. for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
  229. int slabsize = SMALLEST_SLAB << cachind;
  230. debug_text_event ( debug_area, 1, "allc");
  231. debug_int_event ( debug_area, 1, slabsize);
  232. sprintf ( ccw_cache_name[cachind], 
  233.   "%s%d%c", ccw_name_template, slabsize, 0);
  234. ccw_cache[cachind] = 
  235. kmem_cache_create( ccw_cache_name[cachind], 
  236.    slabsize, 0,
  237.    CCW_CACHE_SLAB_TYPE,
  238.    NULL, NULL );
  239. debug_int_event ( debug_area, 1, (long)ccw_cache[cachind]);
  240. if (ccw_cache[cachind] == NULL)
  241. panic ("Allocation of CCW cache failedn");
  242. }
  243. return rc;
  244. }
  245. /* 
  246.  * ccwcache_cleanup
  247.  * called as a cleanup function for the ccw memory management
  248.  */
  249. void
  250. ccwcache_cleanup (void)
  251. {
  252. int cachind;
  253. /* Shrink the caches, if available */
  254. for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
  255. if ( ccw_cache[cachind] ) {
  256. #if 0 /* this is useless and could cause an OOPS in the worst case */
  257. if ( kmem_cache_shrink(ccw_cache[cachind]) == 0 ) {
  258. ccw_cache[cachind] = NULL;
  259. }
  260. #endif
  261. kmem_cache_destroy(ccw_cache[cachind]);
  262. }
  263. }
  264. debug_unregister( debug_area );
  265. }
  266. EXPORT_SYMBOL(ccw_alloc_request);
  267. EXPORT_SYMBOL(ccw_free_request);