pci_insn.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * s390 specific pci instructions
  3. *
  4. * Copyright IBM Corp. 2013
  5. */
  6. #include <linux/export.h>
  7. #include <linux/errno.h>
  8. #include <linux/delay.h>
  9. #include <asm/facility.h>
  10. #include <asm/pci_insn.h>
  11. #include <asm/pci_debug.h>
  12. #include <asm/processor.h>
  13. #define ZPCI_INSN_BUSY_DELAY 1 /* 1 microsecond */
  14. static inline void zpci_err_insn(u8 cc, u8 status, u64 req, u64 offset)
  15. {
  16. struct {
  17. u64 req;
  18. u64 offset;
  19. u8 cc;
  20. u8 status;
  21. } __packed data = {req, offset, cc, status};
  22. zpci_err_hex(&data, sizeof(data));
  23. }
  24. /* Modify PCI Function Controls */
  25. static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
  26. {
  27. u8 cc;
  28. asm volatile (
  29. " .insn rxy,0xe300000000d0,%[req],%[fib]\n"
  30. " ipm %[cc]\n"
  31. " srl %[cc],28\n"
  32. : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
  33. : : "cc");
  34. *status = req >> 24 & 0xff;
  35. return cc;
  36. }
  37. int zpci_mod_fc(u64 req, struct zpci_fib *fib)
  38. {
  39. u8 cc, status;
  40. do {
  41. cc = __mpcifc(req, fib, &status);
  42. if (cc == 2)
  43. msleep(ZPCI_INSN_BUSY_DELAY);
  44. } while (cc == 2);
  45. if (cc)
  46. zpci_err_insn(cc, status, req, 0);
  47. return (cc) ? -EIO : 0;
  48. }
  49. /* Refresh PCI Translations */
  50. static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
  51. {
  52. register u64 __addr asm("2") = addr;
  53. register u64 __range asm("3") = range;
  54. u8 cc;
  55. asm volatile (
  56. " .insn rre,0xb9d30000,%[fn],%[addr]\n"
  57. " ipm %[cc]\n"
  58. " srl %[cc],28\n"
  59. : [cc] "=d" (cc), [fn] "+d" (fn)
  60. : [addr] "d" (__addr), "d" (__range)
  61. : "cc");
  62. *status = fn >> 24 & 0xff;
  63. return cc;
  64. }
  65. int zpci_refresh_trans(u64 fn, u64 addr, u64 range)
  66. {
  67. u8 cc, status;
  68. do {
  69. cc = __rpcit(fn, addr, range, &status);
  70. if (cc == 2)
  71. udelay(ZPCI_INSN_BUSY_DELAY);
  72. } while (cc == 2);
  73. if (cc)
  74. zpci_err_insn(cc, status, addr, range);
  75. return (cc) ? -EIO : 0;
  76. }
  77. /* Set Interruption Controls */
  78. int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc)
  79. {
  80. if (!test_facility(72))
  81. return -EIO;
  82. asm volatile (
  83. " .insn rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
  84. : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused));
  85. return 0;
  86. }
  87. /* PCI Load */
  88. static inline int ____pcilg(u64 *data, u64 req, u64 offset, u8 *status)
  89. {
  90. register u64 __req asm("2") = req;
  91. register u64 __offset asm("3") = offset;
  92. int cc = -ENXIO;
  93. u64 __data;
  94. asm volatile (
  95. " .insn rre,0xb9d20000,%[data],%[req]\n"
  96. "0: ipm %[cc]\n"
  97. " srl %[cc],28\n"
  98. "1:\n"
  99. EX_TABLE(0b, 1b)
  100. : [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req)
  101. : "d" (__offset)
  102. : "cc");
  103. *status = __req >> 24 & 0xff;
  104. *data = __data;
  105. return cc;
  106. }
  107. static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
  108. {
  109. u64 __data;
  110. int cc;
  111. cc = ____pcilg(&__data, req, offset, status);
  112. if (!cc)
  113. *data = __data;
  114. return cc;
  115. }
  116. int zpci_load(u64 *data, u64 req, u64 offset)
  117. {
  118. u8 status;
  119. int cc;
  120. do {
  121. cc = __pcilg(data, req, offset, &status);
  122. if (cc == 2)
  123. udelay(ZPCI_INSN_BUSY_DELAY);
  124. } while (cc == 2);
  125. if (cc)
  126. zpci_err_insn(cc, status, req, offset);
  127. return (cc > 0) ? -EIO : cc;
  128. }
  129. EXPORT_SYMBOL_GPL(zpci_load);
  130. /* PCI Store */
  131. static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
  132. {
  133. register u64 __req asm("2") = req;
  134. register u64 __offset asm("3") = offset;
  135. int cc = -ENXIO;
  136. asm volatile (
  137. " .insn rre,0xb9d00000,%[data],%[req]\n"
  138. "0: ipm %[cc]\n"
  139. " srl %[cc],28\n"
  140. "1:\n"
  141. EX_TABLE(0b, 1b)
  142. : [cc] "+d" (cc), [req] "+d" (__req)
  143. : "d" (__offset), [data] "d" (data)
  144. : "cc");
  145. *status = __req >> 24 & 0xff;
  146. return cc;
  147. }
  148. int zpci_store(u64 data, u64 req, u64 offset)
  149. {
  150. u8 status;
  151. int cc;
  152. do {
  153. cc = __pcistg(data, req, offset, &status);
  154. if (cc == 2)
  155. udelay(ZPCI_INSN_BUSY_DELAY);
  156. } while (cc == 2);
  157. if (cc)
  158. zpci_err_insn(cc, status, req, offset);
  159. return (cc > 0) ? -EIO : cc;
  160. }
  161. EXPORT_SYMBOL_GPL(zpci_store);
  162. /* PCI Store Block */
  163. static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
  164. {
  165. int cc = -ENXIO;
  166. asm volatile (
  167. " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
  168. "0: ipm %[cc]\n"
  169. " srl %[cc],28\n"
  170. "1:\n"
  171. EX_TABLE(0b, 1b)
  172. : [cc] "+d" (cc), [req] "+d" (req)
  173. : [offset] "d" (offset), [data] "Q" (*data)
  174. : "cc");
  175. *status = req >> 24 & 0xff;
  176. return cc;
  177. }
  178. int zpci_store_block(const u64 *data, u64 req, u64 offset)
  179. {
  180. u8 status;
  181. int cc;
  182. do {
  183. cc = __pcistb(data, req, offset, &status);
  184. if (cc == 2)
  185. udelay(ZPCI_INSN_BUSY_DELAY);
  186. } while (cc == 2);
  187. if (cc)
  188. zpci_err_insn(cc, status, req, offset);
  189. return (cc > 0) ? -EIO : cc;
  190. }
  191. EXPORT_SYMBOL_GPL(zpci_store_block);