You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mlx_icmd.c 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /*
  2. * Copyright (C) 2015 Mellanox Technologies Ltd.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER );
  20. #include "../../include/public/mlx_bail.h"
  21. #include "../../include/public/mlx_icmd.h"
  22. #include "../../include/public/mlx_pci_gw.h"
  23. #include "../../include/public/mlx_utils.h"
  24. static
  25. mlx_status
  26. mlx_icmd_get_semaphore(
  27. IN mlx_utils *utils
  28. )
  29. {
  30. mlx_status status = MLX_SUCCESS;
  31. mlx_uint32 retries = 0;
  32. mlx_uint32 semaphore_id;
  33. mlx_uint32 buffer;
  34. if (utils == NULL) {
  35. status = MLX_INVALID_PARAMETER;
  36. goto invalid_param;
  37. }
  38. status = mlx_utils_rand(utils, &semaphore_id);
  39. MLX_CHECK_STATUS(utils, status, rand_err, "failed to get random number");
  40. #define ICMD_GET_SEMAPHORE_TRIES 2560
  41. for (retries = 0 ; retries < ICMD_GET_SEMAPHORE_TRIES ; retries++) {
  42. status = mlx_pci_gw_read( utils, PCI_GW_SPACE_SEMAPHORE,
  43. MLX_ICMD_SEMAPHORE_ADDR, &buffer);
  44. MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd semaphore");
  45. if (buffer != 0) {
  46. mlx_utils_delay_in_ms(10);
  47. continue;
  48. }
  49. mlx_pci_gw_write( utils, PCI_GW_SPACE_SEMAPHORE,
  50. MLX_ICMD_SEMAPHORE_ADDR, semaphore_id);
  51. MLX_CHECK_STATUS(utils, status, set_err, "failed to set icmd semaphore");
  52. status = mlx_pci_gw_read( utils, PCI_GW_SPACE_SEMAPHORE,
  53. MLX_ICMD_SEMAPHORE_ADDR, &buffer);
  54. MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd semaphore");
  55. if (semaphore_id == buffer) {
  56. status = MLX_SUCCESS;
  57. utils->icmd.took_semaphore = TRUE;
  58. break;
  59. }
  60. mlx_utils_delay_in_ms(10);
  61. }
  62. if (semaphore_id != buffer) {
  63. status = MLX_FAILED;
  64. }
  65. read_err:
  66. set_err:
  67. rand_err:
  68. invalid_param:
  69. return status;
  70. }
  71. static
  72. mlx_status
  73. mlx_icmd_clear_semaphore(
  74. IN mlx_utils *utils
  75. )
  76. {
  77. mlx_status status = MLX_SUCCESS;
  78. if (utils == NULL) {
  79. status = MLX_INVALID_PARAMETER;
  80. goto invalid_param;
  81. }
  82. if (utils->icmd.took_semaphore == FALSE) {
  83. goto semaphore_not_taken;
  84. }
  85. status = mlx_pci_gw_write( utils, PCI_GW_SPACE_SEMAPHORE,
  86. MLX_ICMD_SEMAPHORE_ADDR, 0);
  87. MLX_CHECK_STATUS(utils, status, read_err, "failed to clear icmd semaphore");
  88. utils->icmd.took_semaphore = FALSE;
  89. read_err:
  90. semaphore_not_taken:
  91. invalid_param:
  92. return status;
  93. }
  94. static
  95. mlx_status
  96. mlx_icmd_init(
  97. IN mlx_utils *utils
  98. )
  99. {
  100. mlx_status status = MLX_SUCCESS;
  101. if (utils == NULL) {
  102. status = MLX_INVALID_PARAMETER;
  103. goto invalid_param;
  104. }
  105. if (utils->icmd.icmd_opened == TRUE) {
  106. goto already_opened;
  107. }
  108. utils->icmd.took_semaphore = FALSE;
  109. status = mlx_pci_gw_read( utils, PCI_GW_SPACE_ALL_ICMD,
  110. MLX_ICMD_MB_SIZE_ADDR, &utils->icmd.max_cmd_size);
  111. MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd mail box size");
  112. utils->icmd.icmd_opened = TRUE;
  113. read_err:
  114. already_opened:
  115. invalid_param:
  116. return status;
  117. }
  118. static
  119. mlx_status
  120. mlx_icmd_set_opcode(
  121. IN mlx_utils *utils,
  122. IN mlx_uint16 opcode
  123. )
  124. {
  125. mlx_status status = MLX_SUCCESS;
  126. mlx_uint32 buffer;
  127. if (utils == NULL) {
  128. status = MLX_INVALID_PARAMETER;
  129. goto invalid_param;
  130. }
  131. status = mlx_pci_gw_read( utils, PCI_GW_SPACE_ALL_ICMD,
  132. MLX_ICMD_CTRL_ADDR, &buffer);
  133. MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd ctrl");
  134. #define MLX_ICMD_OPCODE_ALIGN 16
  135. #define MLX_ICMD_OPCODE_MASK 0xffff
  136. buffer = buffer & ~(MLX_ICMD_OPCODE_MASK << MLX_ICMD_OPCODE_ALIGN);
  137. buffer = buffer | (opcode << MLX_ICMD_OPCODE_ALIGN);
  138. status = mlx_pci_gw_write( utils, PCI_GW_SPACE_ALL_ICMD,
  139. MLX_ICMD_CTRL_ADDR, buffer);
  140. MLX_CHECK_STATUS(utils, status, write_err, "failed to write icmd ctrl");
  141. write_err:
  142. read_err:
  143. invalid_param:
  144. return status;
  145. }
  146. static
  147. mlx_status
  148. mlx_icmd_go(
  149. IN mlx_utils *utils
  150. )
  151. {
  152. mlx_status status = MLX_SUCCESS;
  153. mlx_uint32 buffer;
  154. mlx_uint32 busy;
  155. mlx_uint32 wait_iteration = 0;
  156. if (utils == NULL) {
  157. status = MLX_INVALID_PARAMETER;
  158. goto invalid_param;
  159. }
  160. status = mlx_pci_gw_read( utils, PCI_GW_SPACE_ALL_ICMD,
  161. MLX_ICMD_CTRL_ADDR, &buffer);
  162. MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd ctrl");
  163. #define MLX_ICMD_BUSY_ALIGN 0
  164. #define MLX_ICMD_BUSY_MASK 0x1
  165. busy = (buffer >> MLX_ICMD_BUSY_ALIGN) & MLX_ICMD_BUSY_MASK;
  166. if (busy != 0) {
  167. status = MLX_FAILED;
  168. goto already_busy;
  169. }
  170. buffer = buffer | (1 << MLX_ICMD_BUSY_ALIGN);
  171. status = mlx_pci_gw_write( utils, PCI_GW_SPACE_ALL_ICMD,
  172. MLX_ICMD_CTRL_ADDR, buffer);
  173. MLX_CHECK_STATUS(utils, status, write_err, "failed to write icmd ctrl");
  174. #define MLX_ICMD_BUSY_MAX_ITERATIONS 1024
  175. do {
  176. if (++wait_iteration > MLX_ICMD_BUSY_MAX_ITERATIONS) {
  177. status = MLX_FAILED;
  178. MLX_DEBUG_ERROR(utils, "ICMD time out");
  179. goto busy_timeout;
  180. }
  181. mlx_utils_delay_in_ms(10);
  182. status = mlx_pci_gw_read( utils, PCI_GW_SPACE_ALL_ICMD,
  183. MLX_ICMD_CTRL_ADDR, &buffer);
  184. MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd ctrl");
  185. busy = (buffer >> MLX_ICMD_BUSY_ALIGN) & MLX_ICMD_BUSY_MASK;
  186. } while (busy != 0);
  187. busy_timeout:
  188. write_err:
  189. already_busy:
  190. read_err:
  191. invalid_param:
  192. return status;
  193. }
  194. static
  195. mlx_status
  196. mlx_icmd_get_status(
  197. IN mlx_utils *utils,
  198. OUT mlx_uint32 *out_status
  199. )
  200. {
  201. mlx_status status = MLX_SUCCESS;
  202. mlx_uint32 buffer;
  203. if (utils == NULL || out_status == NULL) {
  204. status = MLX_INVALID_PARAMETER;
  205. goto invalid_param;
  206. }
  207. status = mlx_pci_gw_read( utils, PCI_GW_SPACE_ALL_ICMD,
  208. MLX_ICMD_CTRL_ADDR, &buffer);
  209. MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd ctrl");
  210. #define MLX_ICMD_STATUS_ALIGN 8
  211. #define MLX_ICMD_STATUS_MASK 0xff
  212. *out_status = (buffer >> MLX_ICMD_STATUS_ALIGN) & MLX_ICMD_STATUS_MASK;
  213. read_err:
  214. invalid_param:
  215. return status;
  216. }
  217. static
  218. mlx_status
  219. mlx_icmd_write_buffer(
  220. IN mlx_utils *utils,
  221. IN mlx_void* data,
  222. IN mlx_uint32 data_size
  223. )
  224. {
  225. mlx_status status = MLX_SUCCESS;
  226. mlx_uint32 data_offset = 0;
  227. mlx_size dword_size = sizeof(mlx_uint32);
  228. if (utils == NULL || data == NULL) {
  229. status = MLX_INVALID_PARAMETER;
  230. goto invalid_param;
  231. }
  232. for (data_offset = 0 ; data_offset*dword_size < data_size ; data_offset++) {
  233. status = mlx_pci_gw_write( utils, PCI_GW_SPACE_ALL_ICMD,
  234. MLX_ICMD_MB_ADDR + data_offset*dword_size,
  235. ((mlx_uint32*)data)[data_offset]);
  236. MLX_CHECK_STATUS(utils, status, write_err, "failed to write icmd MB");
  237. }
  238. write_err:
  239. invalid_param:
  240. return status;
  241. }
  242. static
  243. mlx_status
  244. mlx_icmd_read_buffer(
  245. IN mlx_utils *utils,
  246. OUT mlx_void* data,
  247. IN mlx_uint32 data_size
  248. )
  249. {
  250. mlx_status status = MLX_SUCCESS;
  251. mlx_uint32 data_offset = 0;
  252. mlx_size dword_size = sizeof(mlx_uint32);
  253. if (utils == NULL || data == NULL) {
  254. status = MLX_INVALID_PARAMETER;
  255. goto invalid_param;
  256. }
  257. for (data_offset = 0 ; data_offset*dword_size < data_size ; data_offset++) {
  258. status = mlx_pci_gw_read( utils, PCI_GW_SPACE_ALL_ICMD,
  259. MLX_ICMD_MB_ADDR + data_offset*dword_size,
  260. (mlx_uint32*)data + data_offset);
  261. MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd MB");
  262. }
  263. read_err:
  264. invalid_param:
  265. return status;
  266. }
  267. mlx_status
  268. mlx_icmd_send_command(
  269. IN mlx_utils *utils,
  270. IN mlx_uint16 opcode,
  271. IN OUT mlx_void* data,
  272. IN mlx_uint32 write_data_size,
  273. IN mlx_uint32 read_data_size
  274. )
  275. {
  276. mlx_status status = MLX_SUCCESS;
  277. mlx_uint32 icmd_status;
  278. if (utils == NULL || data == NULL) {
  279. status = MLX_INVALID_PARAMETER;
  280. goto invalid_param;
  281. }
  282. status = mlx_icmd_init(utils);
  283. MLX_CHECK_STATUS(utils, status, open_err, "failed to open icmd");
  284. if (write_data_size > utils->icmd.max_cmd_size ||
  285. read_data_size > utils->icmd.max_cmd_size) {
  286. status = MLX_INVALID_PARAMETER;
  287. goto size_err;
  288. }
  289. status = mlx_icmd_get_semaphore(utils);
  290. MLX_CHECK_STATUS(utils, status, semaphore_err, "failed to get icmd semaphore");
  291. status = mlx_icmd_set_opcode(utils, opcode);
  292. MLX_CHECK_STATUS(utils, status, opcode_err, "failed to set icmd opcode");
  293. if (write_data_size != 0) {
  294. status = mlx_icmd_write_buffer(utils, data, write_data_size);
  295. MLX_CHECK_STATUS(utils, status, opcode_err, "failed to write icmd MB");
  296. }
  297. status = mlx_icmd_go(utils);
  298. MLX_CHECK_STATUS(utils, status, go_err, "failed to activate icmd");
  299. status = mlx_icmd_get_status(utils, &icmd_status);
  300. MLX_CHECK_STATUS(utils, status, get_status_err, "failed to set icmd opcode");
  301. if (icmd_status != 0) {
  302. MLX_DEBUG_ERROR(utils, "icmd failed with status = %d\n", icmd_status);
  303. status = MLX_FAILED;
  304. goto icmd_failed;
  305. }
  306. if (read_data_size != 0) {
  307. status = mlx_icmd_read_buffer(utils, data, read_data_size);
  308. MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd MB");
  309. }
  310. read_err:
  311. icmd_failed:
  312. get_status_err:
  313. go_err:
  314. opcode_err:
  315. mlx_icmd_clear_semaphore(utils);
  316. semaphore_err:
  317. size_err:
  318. open_err:
  319. invalid_param:
  320. return status;
  321. }