pci_insn.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. if (!cc)
  105. *data = __data;
  106. return cc;
  107. }
  108. int zpci_load(u64 *data, u64 req, u64 offset)
  109. {
  110. u8 status;
  111. int cc;
  112. do {
  113. cc = __pcilg(data, req, offset, &status);
  114. if (cc == 2)
  115. udelay(ZPCI_INSN_BUSY_DELAY);
  116. } while (cc == 2);
  117. if (cc)
  118. zpci_err_insn(cc, status, req, offset);
  119. return (cc > 0) ? -EIO : cc;
  120. }
  121. EXPORT_SYMBOL_GPL(zpci_load);
  122. /* PCI Store */
  123. static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
  124. {
  125. register u64 __req asm("2") = req;
  126. register u64 __offset asm("3") = offset;
  127. int cc = -ENXIO;
  128. asm volatile (
  129. " .insn rre,0xb9d00000,%[data],%[req]\n"
  130. "0: ipm %[cc]\n"
  131. " srl %[cc],28\n"
  132. "1:\n"
  133. EX_TABLE(0b, 1b)
  134. : [cc] "+d" (cc), [req] "+d" (__req)
  135. : "d" (__offset), [data] "d" (data)
  136. : "cc");
  137. *status = __req >> 24 & 0xff;
  138. return cc;
  139. }
  140. int zpci_store(u64 data, u64 req, u64 offset)
  141. {
  142. u8 status;
  143. int cc;
  144. do {
  145. cc = __pcistg(data, req, offset, &status);
  146. if (cc == 2)
  147. udelay(ZPCI_INSN_BUSY_DELAY);
  148. } while (cc == 2);
  149. if (cc)
  150. zpci_err_insn(cc, status, req, offset);
  151. return (cc > 0) ? -EIO : cc;
  152. }
  153. EXPORT_SYMBOL_GPL(zpci_store);
  154. /* PCI Store Block */
  155. static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
  156. {
  157. int cc = -ENXIO;
  158. asm volatile (
  159. " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
  160. "0: ipm %[cc]\n"
  161. " srl %[cc],28\n"
  162. "1:\n"
  163. EX_TABLE(0b, 1b)
  164. : [cc] "+d" (cc), [req] "+d" (req)
  165. : [offset] "d" (offset), [data] "Q" (*data)
  166. : "cc");
  167. *status = req >> 24 & 0xff;
  168. return cc;
  169. }
  170. int zpci_store_block(const u64 *data, u64 req, u64 offset)
  171. {
  172. u8 status;
  173. int cc;
  174. do {
  175. cc = __pcistb(data, req, offset, &status);
  176. if (cc == 2)
  177. udelay(ZPCI_INSN_BUSY_DELAY);
  178. } while (cc == 2);
  179. if (cc)
  180. zpci_err_insn(cc, status, req, offset);
  181. return (cc > 0) ? -EIO : cc;
  182. }
  183. EXPORT_SYMBOL_GPL(zpci_store_block);