fcx.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Functions for assembling fcx enabled I/O control blocks.
  4. *
  5. * Copyright IBM Corp. 2008
  6. * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/types.h>
  10. #include <linux/string.h>
  11. #include <linux/io.h>
  12. #include <linux/errno.h>
  13. #include <linux/err.h>
  14. #include <linux/module.h>
  15. #include <asm/fcx.h>
  16. #include "cio.h"
  17. /**
  18. * tcw_get_intrg - return pointer to associated interrogate tcw
  19. * @tcw: pointer to the original tcw
  20. *
  21. * Return a pointer to the interrogate tcw associated with the specified tcw
  22. * or %NULL if there is no associated interrogate tcw.
  23. */
  24. struct tcw *tcw_get_intrg(struct tcw *tcw)
  25. {
  26. return dma32_to_virt(tcw->intrg);
  27. }
  28. EXPORT_SYMBOL(tcw_get_intrg);
  29. /**
  30. * tcw_get_data - return pointer to input/output data associated with tcw
  31. * @tcw: pointer to the tcw
  32. *
  33. * Return the input or output data address specified in the tcw depending
  34. * on whether the r-bit or the w-bit is set. If neither bit is set, return
  35. * %NULL.
  36. */
  37. void *tcw_get_data(struct tcw *tcw)
  38. {
  39. if (tcw->r)
  40. return dma64_to_virt(tcw->input);
  41. if (tcw->w)
  42. return dma64_to_virt(tcw->output);
  43. return NULL;
  44. }
  45. EXPORT_SYMBOL(tcw_get_data);
  46. /**
  47. * tcw_get_tccb - return pointer to tccb associated with tcw
  48. * @tcw: pointer to the tcw
  49. *
  50. * Return pointer to the tccb associated with this tcw.
  51. */
  52. struct tccb *tcw_get_tccb(struct tcw *tcw)
  53. {
  54. return dma64_to_virt(tcw->tccb);
  55. }
  56. EXPORT_SYMBOL(tcw_get_tccb);
  57. /**
  58. * tcw_get_tsb - return pointer to tsb associated with tcw
  59. * @tcw: pointer to the tcw
  60. *
  61. * Return pointer to the tsb associated with this tcw.
  62. */
  63. struct tsb *tcw_get_tsb(struct tcw *tcw)
  64. {
  65. return dma64_to_virt(tcw->tsb);
  66. }
  67. EXPORT_SYMBOL(tcw_get_tsb);
  68. /**
  69. * tcw_init - initialize tcw data structure
  70. * @tcw: pointer to the tcw to be initialized
  71. * @r: initial value of the r-bit
  72. * @w: initial value of the w-bit
  73. *
  74. * Initialize all fields of the specified tcw data structure with zero and
  75. * fill in the format, flags, r and w fields.
  76. */
  77. void tcw_init(struct tcw *tcw, int r, int w)
  78. {
  79. memset(tcw, 0, sizeof(struct tcw));
  80. tcw->format = TCW_FORMAT_DEFAULT;
  81. tcw->flags = TCW_FLAGS_TIDAW_FORMAT(TCW_TIDAW_FORMAT_DEFAULT);
  82. if (r)
  83. tcw->r = 1;
  84. if (w)
  85. tcw->w = 1;
  86. }
  87. EXPORT_SYMBOL(tcw_init);
  88. static inline size_t tca_size(struct tccb *tccb)
  89. {
  90. return tccb->tcah.tcal - 12;
  91. }
  92. static u32 calc_dcw_count(struct tccb *tccb)
  93. {
  94. int offset;
  95. struct dcw *dcw;
  96. u32 count = 0;
  97. size_t size;
  98. size = tca_size(tccb);
  99. for (offset = 0; offset < size;) {
  100. dcw = (struct dcw *) &tccb->tca[offset];
  101. count += dcw->count;
  102. if (!(dcw->flags & DCW_FLAGS_CC))
  103. break;
  104. offset += sizeof(struct dcw) + ALIGN((int) dcw->cd_count, 4);
  105. }
  106. return count;
  107. }
  108. static u32 calc_cbc_size(struct tidaw *tidaw, int num)
  109. {
  110. int i;
  111. u32 cbc_data;
  112. u32 cbc_count = 0;
  113. u64 data_count = 0;
  114. for (i = 0; i < num; i++) {
  115. if (tidaw[i].flags & TIDAW_FLAGS_LAST)
  116. break;
  117. /* TODO: find out if padding applies to total of data
  118. * transferred or data transferred by this tidaw. Assumption:
  119. * applies to total. */
  120. data_count += tidaw[i].count;
  121. if (tidaw[i].flags & TIDAW_FLAGS_INSERT_CBC) {
  122. cbc_data = 4 + ALIGN(data_count, 4) - data_count;
  123. cbc_count += cbc_data;
  124. data_count += cbc_data;
  125. }
  126. }
  127. return cbc_count;
  128. }
  129. /**
  130. * tcw_finalize - finalize tcw length fields and tidaw list
  131. * @tcw: pointer to the tcw
  132. * @num_tidaws: the number of tidaws used to address input/output data or zero
  133. * if no tida is used
  134. *
  135. * Calculate the input-/output-count and tccbl field in the tcw, add a
  136. * tcat the tccb and terminate the data tidaw list if used.
  137. *
  138. * Note: in case input- or output-tida is used, the tidaw-list must be stored
  139. * in contiguous storage (no ttic). The tcal field in the tccb must be
  140. * up-to-date.
  141. */
  142. void tcw_finalize(struct tcw *tcw, int num_tidaws)
  143. {
  144. struct tidaw *tidaw;
  145. struct tccb *tccb;
  146. struct tccb_tcat *tcat;
  147. u32 count;
  148. /* Terminate tidaw list. */
  149. tidaw = tcw_get_data(tcw);
  150. if (num_tidaws > 0)
  151. tidaw[num_tidaws - 1].flags |= TIDAW_FLAGS_LAST;
  152. /* Add tcat to tccb. */
  153. tccb = tcw_get_tccb(tcw);
  154. tcat = (struct tccb_tcat *) &tccb->tca[tca_size(tccb)];
  155. memset(tcat, 0, sizeof(*tcat));
  156. /* Calculate tcw input/output count and tcat transport count. */
  157. count = calc_dcw_count(tccb);
  158. if (tcw->w && (tcw->flags & TCW_FLAGS_OUTPUT_TIDA))
  159. count += calc_cbc_size(tidaw, num_tidaws);
  160. if (tcw->r)
  161. tcw->input_count = count;
  162. else if (tcw->w)
  163. tcw->output_count = count;
  164. tcat->count = ALIGN(count, 4) + 4;
  165. /* Calculate tccbl. */
  166. tcw->tccbl = (sizeof(struct tccb) + tca_size(tccb) +
  167. sizeof(struct tccb_tcat) - 20) >> 2;
  168. }
  169. EXPORT_SYMBOL(tcw_finalize);
  170. /**
  171. * tcw_set_intrg - set the interrogate tcw address of a tcw
  172. * @tcw: the tcw address
  173. * @intrg_tcw: the address of the interrogate tcw
  174. *
  175. * Set the address of the interrogate tcw in the specified tcw.
  176. */
  177. void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw)
  178. {
  179. tcw->intrg = virt_to_dma32(intrg_tcw);
  180. }
  181. EXPORT_SYMBOL(tcw_set_intrg);
  182. /**
  183. * tcw_set_data - set data address and tida flag of a tcw
  184. * @tcw: the tcw address
  185. * @data: the data address
  186. * @use_tidal: zero of the data address specifies a contiguous block of data,
  187. * non-zero if it specifies a list if tidaws.
  188. *
  189. * Set the input/output data address of a tcw (depending on the value of the
  190. * r-flag and w-flag). If @use_tidal is non-zero, the corresponding tida flag
  191. * is set as well.
  192. */
  193. void tcw_set_data(struct tcw *tcw, void *data, int use_tidal)
  194. {
  195. if (tcw->r) {
  196. tcw->input = virt_to_dma64(data);
  197. if (use_tidal)
  198. tcw->flags |= TCW_FLAGS_INPUT_TIDA;
  199. } else if (tcw->w) {
  200. tcw->output = virt_to_dma64(data);
  201. if (use_tidal)
  202. tcw->flags |= TCW_FLAGS_OUTPUT_TIDA;
  203. }
  204. }
  205. EXPORT_SYMBOL(tcw_set_data);
  206. /**
  207. * tcw_set_tccb - set tccb address of a tcw
  208. * @tcw: the tcw address
  209. * @tccb: the tccb address
  210. *
  211. * Set the address of the tccb in the specified tcw.
  212. */
  213. void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb)
  214. {
  215. tcw->tccb = virt_to_dma64(tccb);
  216. }
  217. EXPORT_SYMBOL(tcw_set_tccb);
  218. /**
  219. * tcw_set_tsb - set tsb address of a tcw
  220. * @tcw: the tcw address
  221. * @tsb: the tsb address
  222. *
  223. * Set the address of the tsb in the specified tcw.
  224. */
  225. void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb)
  226. {
  227. tcw->tsb = virt_to_dma64(tsb);
  228. }
  229. EXPORT_SYMBOL(tcw_set_tsb);
  230. /**
  231. * tccb_init - initialize tccb
  232. * @tccb: the tccb address
  233. * @size: the maximum size of the tccb
  234. * @sac: the service-action-code to be user
  235. *
  236. * Initialize the header of the specified tccb by resetting all values to zero
  237. * and filling in defaults for format, sac and initial tcal fields.
  238. */
  239. void tccb_init(struct tccb *tccb, size_t size, u32 sac)
  240. {
  241. memset(tccb, 0, size);
  242. tccb->tcah.format = TCCB_FORMAT_DEFAULT;
  243. tccb->tcah.sac = sac;
  244. tccb->tcah.tcal = 12;
  245. }
  246. EXPORT_SYMBOL(tccb_init);
  247. /**
  248. * tsb_init - initialize tsb
  249. * @tsb: the tsb address
  250. *
  251. * Initialize the specified tsb by resetting all values to zero.
  252. */
  253. void tsb_init(struct tsb *tsb)
  254. {
  255. memset(tsb, 0, sizeof(*tsb));
  256. }
  257. EXPORT_SYMBOL(tsb_init);
  258. /**
  259. * tccb_add_dcw - add a dcw to the tccb
  260. * @tccb: the tccb address
  261. * @tccb_size: the maximum tccb size
  262. * @cmd: the dcw command
  263. * @flags: flags for the dcw
  264. * @cd: pointer to control data for this dcw or NULL if none is required
  265. * @cd_count: number of control data bytes for this dcw
  266. * @count: number of data bytes for this dcw
  267. *
  268. * Add a new dcw to the specified tccb by writing the dcw information specified
  269. * by @cmd, @flags, @cd, @cd_count and @count to the tca of the tccb. Return
  270. * a pointer to the newly added dcw on success or -%ENOSPC if the new dcw
  271. * would exceed the available space as defined by @tccb_size.
  272. *
  273. * Note: the tcal field of the tccb header will be updates to reflect added
  274. * content.
  275. */
  276. struct dcw *tccb_add_dcw(struct tccb *tccb, size_t tccb_size, u8 cmd, u8 flags,
  277. void *cd, u8 cd_count, u32 count)
  278. {
  279. struct dcw *dcw;
  280. int size;
  281. int tca_offset;
  282. /* Check for space. */
  283. tca_offset = tca_size(tccb);
  284. size = ALIGN(sizeof(struct dcw) + cd_count, 4);
  285. if (sizeof(struct tccb_tcah) + tca_offset + size +
  286. sizeof(struct tccb_tcat) > tccb_size)
  287. return ERR_PTR(-ENOSPC);
  288. /* Add dcw to tca. */
  289. dcw = (struct dcw *) &tccb->tca[tca_offset];
  290. memset(dcw, 0, size);
  291. dcw->cmd = cmd;
  292. dcw->flags = flags;
  293. dcw->count = count;
  294. dcw->cd_count = cd_count;
  295. if (cd)
  296. memcpy(&dcw->cd[0], cd, cd_count);
  297. tccb->tcah.tcal += size;
  298. return dcw;
  299. }
  300. EXPORT_SYMBOL(tccb_add_dcw);
  301. /**
  302. * tcw_add_tidaw - add a tidaw to a tcw
  303. * @tcw: the tcw address
  304. * @num_tidaws: the current number of tidaws
  305. * @flags: flags for the new tidaw
  306. * @addr: address value for the new tidaw
  307. * @count: count value for the new tidaw
  308. *
  309. * Add a new tidaw to the input/output data tidaw-list of the specified tcw
  310. * (depending on the value of the r-flag and w-flag) and return a pointer to
  311. * the new tidaw.
  312. *
  313. * Note: the tidaw-list is assumed to be contiguous with no ttics. The caller
  314. * must ensure that there is enough space for the new tidaw. The last-tidaw
  315. * flag for the last tidaw in the list will be set by tcw_finalize.
  316. */
  317. struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags,
  318. void *addr, u32 count)
  319. {
  320. struct tidaw *tidaw;
  321. /* Add tidaw to tidaw-list. */
  322. tidaw = ((struct tidaw *) tcw_get_data(tcw)) + num_tidaws;
  323. memset(tidaw, 0, sizeof(struct tidaw));
  324. tidaw->flags = flags;
  325. tidaw->count = count;
  326. tidaw->addr = virt_to_dma64(addr);
  327. return tidaw;
  328. }
  329. EXPORT_SYMBOL(tcw_add_tidaw);