idals.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * File...........: linux/include/asm-s390x/idals.h
  3. * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  4. * Martin Schwidefsky <schwidefsky@de.ibm.com>
  5. * Bugreports.to..: <Linux390@de.ibm.com>
  6. * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
  7. * History of changes
  8. * 07/24/00 new file
  9. * 05/04/02 code restructuring.
  10. */
  11. #ifndef _S390_IDALS_H
  12. #define _S390_IDALS_H
  13. #include <linux/errno.h>
  14. #include <linux/err.h>
  15. #include <linux/types.h>
  16. #include <linux/slab.h>
  17. #include <asm/cio.h>
  18. #include <asm/uaccess.h>
  19. #ifdef __s390x__
  20. #define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
  21. #else
  22. #define IDA_SIZE_LOG 11 /* 11 for 2k , 12 for 4k */
  23. #endif
  24. #define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
  25. /*
  26. * Test if an address/length pair needs an idal list.
  27. */
  28. static inline int
  29. idal_is_needed(void *vaddr, unsigned int length)
  30. {
  31. #ifdef __s390x__
  32. return ((__pa(vaddr) + length - 1) >> 31) != 0;
  33. #else
  34. return 0;
  35. #endif
  36. }
  37. /*
  38. * Return the number of idal words needed for an address/length pair.
  39. */
  40. static inline unsigned int
  41. idal_nr_words(void *vaddr, unsigned int length)
  42. {
  43. #ifdef __s390x__
  44. if (idal_is_needed(vaddr, length))
  45. return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length +
  46. (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
  47. #endif
  48. return 0;
  49. }
  50. /*
  51. * Create the list of idal words for an address/length pair.
  52. */
  53. static inline unsigned long *
  54. idal_create_words(unsigned long *idaws, void *vaddr, unsigned int length)
  55. {
  56. #ifdef __s390x__
  57. unsigned long paddr;
  58. unsigned int cidaw;
  59. paddr = __pa(vaddr);
  60. cidaw = ((paddr & (IDA_BLOCK_SIZE-1)) + length +
  61. (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
  62. *idaws++ = paddr;
  63. paddr &= -IDA_BLOCK_SIZE;
  64. while (--cidaw > 0) {
  65. paddr += IDA_BLOCK_SIZE;
  66. *idaws++ = paddr;
  67. }
  68. #endif
  69. return idaws;
  70. }
  71. /*
  72. * Sets the address of the data in CCW.
  73. * If necessary it allocates an IDAL and sets the appropriate flags.
  74. */
  75. static inline int
  76. set_normalized_cda(struct ccw1 * ccw, void *vaddr)
  77. {
  78. #ifdef __s390x__
  79. unsigned int nridaws;
  80. unsigned long *idal;
  81. if (ccw->flags & CCW_FLAG_IDA)
  82. return -EINVAL;
  83. nridaws = idal_nr_words(vaddr, ccw->count);
  84. if (nridaws > 0) {
  85. idal = kmalloc(nridaws * sizeof(unsigned long),
  86. GFP_ATOMIC | GFP_DMA );
  87. if (idal == NULL)
  88. return -ENOMEM;
  89. idal_create_words(idal, vaddr, ccw->count);
  90. ccw->flags |= CCW_FLAG_IDA;
  91. vaddr = idal;
  92. }
  93. #endif
  94. ccw->cda = (__u32)(unsigned long) vaddr;
  95. return 0;
  96. }
  97. /*
  98. * Releases any allocated IDAL related to the CCW.
  99. */
  100. static inline void
  101. clear_normalized_cda(struct ccw1 * ccw)
  102. {
  103. #ifdef __s390x__
  104. if (ccw->flags & CCW_FLAG_IDA) {
  105. kfree((void *)(unsigned long) ccw->cda);
  106. ccw->flags &= ~CCW_FLAG_IDA;
  107. }
  108. #endif
  109. ccw->cda = 0;
  110. }
  111. /*
  112. * Idal buffer extension
  113. */
  114. struct idal_buffer {
  115. size_t size;
  116. size_t page_order;
  117. void *data[0];
  118. };
  119. /*
  120. * Allocate an idal buffer
  121. */
  122. static inline struct idal_buffer *
  123. idal_buffer_alloc(size_t size, int page_order)
  124. {
  125. struct idal_buffer *ib;
  126. int nr_chunks, nr_ptrs, i;
  127. nr_ptrs = (size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_LOG;
  128. nr_chunks = (4096 << page_order) >> IDA_SIZE_LOG;
  129. ib = kmalloc(sizeof(struct idal_buffer) + nr_ptrs*sizeof(void *),
  130. GFP_DMA | GFP_KERNEL);
  131. if (ib == NULL)
  132. return ERR_PTR(-ENOMEM);
  133. ib->size = size;
  134. ib->page_order = page_order;
  135. for (i = 0; i < nr_ptrs; i++) {
  136. if ((i & (nr_chunks - 1)) != 0) {
  137. ib->data[i] = ib->data[i-1] + IDA_BLOCK_SIZE;
  138. continue;
  139. }
  140. ib->data[i] = (void *)
  141. __get_free_pages(GFP_KERNEL, page_order);
  142. if (ib->data[i] != NULL)
  143. continue;
  144. // Not enough memory
  145. while (i >= nr_chunks) {
  146. i -= nr_chunks;
  147. free_pages((unsigned long) ib->data[i],
  148. ib->page_order);
  149. }
  150. kfree(ib);
  151. return ERR_PTR(-ENOMEM);
  152. }
  153. return ib;
  154. }
  155. /*
  156. * Free an idal buffer.
  157. */
  158. static inline void
  159. idal_buffer_free(struct idal_buffer *ib)
  160. {
  161. int nr_chunks, nr_ptrs, i;
  162. nr_ptrs = (ib->size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_LOG;
  163. nr_chunks = (4096 << ib->page_order) >> IDA_SIZE_LOG;
  164. for (i = 0; i < nr_ptrs; i += nr_chunks)
  165. free_pages((unsigned long) ib->data[i], ib->page_order);
  166. kfree(ib);
  167. }
  168. /*
  169. * Test if a idal list is really needed.
  170. */
  171. static inline int
  172. __idal_buffer_is_needed(struct idal_buffer *ib)
  173. {
  174. #ifdef __s390x__
  175. return ib->size > (4096ul << ib->page_order) ||
  176. idal_is_needed(ib->data[0], ib->size);
  177. #else
  178. return ib->size > (4096ul << ib->page_order);
  179. #endif
  180. }
  181. /*
  182. * Set channel data address to idal buffer.
  183. */
  184. static inline void
  185. idal_buffer_set_cda(struct idal_buffer *ib, struct ccw1 *ccw)
  186. {
  187. if (__idal_buffer_is_needed(ib)) {
  188. // setup idals;
  189. ccw->cda = (u32)(addr_t) ib->data;
  190. ccw->flags |= CCW_FLAG_IDA;
  191. } else
  192. // we do not need idals - use direct addressing
  193. ccw->cda = (u32)(addr_t) ib->data[0];
  194. ccw->count = ib->size;
  195. }
  196. /*
  197. * Copy count bytes from an idal buffer to user memory
  198. */
  199. static inline size_t
  200. idal_buffer_to_user(struct idal_buffer *ib, void __user *to, size_t count)
  201. {
  202. size_t left;
  203. int i;
  204. BUG_ON(count > ib->size);
  205. for (i = 0; count > IDA_BLOCK_SIZE; i++) {
  206. left = copy_to_user(to, ib->data[i], IDA_BLOCK_SIZE);
  207. if (left)
  208. return left + count - IDA_BLOCK_SIZE;
  209. to = (void __user *) to + IDA_BLOCK_SIZE;
  210. count -= IDA_BLOCK_SIZE;
  211. }
  212. return copy_to_user(to, ib->data[i], count);
  213. }
  214. /*
  215. * Copy count bytes from user memory to an idal buffer
  216. */
  217. static inline size_t
  218. idal_buffer_from_user(struct idal_buffer *ib, const void __user *from, size_t count)
  219. {
  220. size_t left;
  221. int i;
  222. BUG_ON(count > ib->size);
  223. for (i = 0; count > IDA_BLOCK_SIZE; i++) {
  224. left = copy_from_user(ib->data[i], from, IDA_BLOCK_SIZE);
  225. if (left)
  226. return left + count - IDA_BLOCK_SIZE;
  227. from = (void __user *) from + IDA_BLOCK_SIZE;
  228. count -= IDA_BLOCK_SIZE;
  229. }
  230. return copy_from_user(ib->data[i], from, count);
  231. }
  232. #endif