iosm_ipc_devlink.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2020-2021 Intel Corporation.
  4. */
  5. #include <linux/vmalloc.h>
  6. #include "iosm_ipc_chnl_cfg.h"
  7. #include "iosm_ipc_coredump.h"
  8. #include "iosm_ipc_devlink.h"
  9. #include "iosm_ipc_flash.h"
  10. /* Coredump list */
  11. static struct iosm_coredump_file_info list[IOSM_NOF_CD_REGION] = {
  12. {"report.json", REPORT_JSON_SIZE,},
  13. {"coredump.fcd", COREDUMP_FCD_SIZE,},
  14. {"cdd.log", CDD_LOG_SIZE,},
  15. {"eeprom.bin", EEPROM_BIN_SIZE,},
  16. {"bootcore_trace.bin", BOOTCORE_TRC_BIN_SIZE,},
  17. {"bootcore_prev_trace.bin", BOOTCORE_PREV_TRC_BIN_SIZE,},
  18. };
  19. /* Get the param values for the specific param ID's */
  20. static int ipc_devlink_get_param(struct devlink *dl, u32 id,
  21. struct devlink_param_gset_ctx *ctx)
  22. {
  23. struct iosm_devlink *ipc_devlink = devlink_priv(dl);
  24. if (id == IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH)
  25. ctx->val.vu8 = ipc_devlink->param.erase_full_flash;
  26. return 0;
  27. }
  28. /* Set the param values for the specific param ID's */
  29. static int ipc_devlink_set_param(struct devlink *dl, u32 id,
  30. struct devlink_param_gset_ctx *ctx,
  31. struct netlink_ext_ack *extack)
  32. {
  33. struct iosm_devlink *ipc_devlink = devlink_priv(dl);
  34. if (id == IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH)
  35. ipc_devlink->param.erase_full_flash = ctx->val.vu8;
  36. return 0;
  37. }
  38. /* Devlink param structure array */
  39. static const struct devlink_param iosm_devlink_params[] = {
  40. DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH,
  41. "erase_full_flash", DEVLINK_PARAM_TYPE_BOOL,
  42. BIT(DEVLINK_PARAM_CMODE_RUNTIME),
  43. ipc_devlink_get_param, ipc_devlink_set_param,
  44. NULL),
  45. };
  46. /* Get devlink flash component type */
  47. static enum iosm_flash_comp_type
  48. ipc_devlink_get_flash_comp_type(const char comp_str[], u32 len)
  49. {
  50. enum iosm_flash_comp_type fls_type;
  51. if (!strncmp("PSI", comp_str, len))
  52. fls_type = FLASH_COMP_TYPE_PSI;
  53. else if (!strncmp("EBL", comp_str, len))
  54. fls_type = FLASH_COMP_TYPE_EBL;
  55. else if (!strncmp("FLS", comp_str, len))
  56. fls_type = FLASH_COMP_TYPE_FLS;
  57. else
  58. fls_type = FLASH_COMP_TYPE_INVAL;
  59. return fls_type;
  60. }
  61. /* Function triggered on devlink flash command
  62. * Flash update function which calls multiple functions based on
  63. * component type specified in the flash command
  64. */
  65. static int ipc_devlink_flash_update(struct devlink *devlink,
  66. struct devlink_flash_update_params *params,
  67. struct netlink_ext_ack *extack)
  68. {
  69. struct iosm_devlink *ipc_devlink = devlink_priv(devlink);
  70. enum iosm_flash_comp_type fls_type;
  71. struct iosm_devlink_image *header;
  72. int rc = -EINVAL;
  73. u8 *mdm_rsp;
  74. header = (struct iosm_devlink_image *)params->fw->data;
  75. if (!header || params->fw->size <= IOSM_DEVLINK_HDR_SIZE ||
  76. (memcmp(header->magic_header, IOSM_DEVLINK_MAGIC_HEADER,
  77. IOSM_DEVLINK_MAGIC_HEADER_LEN) != 0))
  78. return -EINVAL;
  79. mdm_rsp = kzalloc(IOSM_EBL_DW_PACK_SIZE, GFP_KERNEL);
  80. if (!mdm_rsp)
  81. return -ENOMEM;
  82. fls_type = ipc_devlink_get_flash_comp_type(header->image_type,
  83. IOSM_DEVLINK_MAX_IMG_LEN);
  84. switch (fls_type) {
  85. case FLASH_COMP_TYPE_PSI:
  86. rc = ipc_flash_boot_psi(ipc_devlink, params->fw);
  87. break;
  88. case FLASH_COMP_TYPE_EBL:
  89. rc = ipc_flash_boot_ebl(ipc_devlink, params->fw);
  90. if (rc)
  91. break;
  92. rc = ipc_flash_boot_set_capabilities(ipc_devlink, mdm_rsp);
  93. if (rc)
  94. break;
  95. rc = ipc_flash_read_swid(ipc_devlink, mdm_rsp);
  96. break;
  97. case FLASH_COMP_TYPE_FLS:
  98. rc = ipc_flash_send_fls(ipc_devlink, params->fw, mdm_rsp);
  99. break;
  100. default:
  101. devlink_flash_update_status_notify(devlink, "Invalid component",
  102. NULL, 0, 0);
  103. break;
  104. }
  105. if (!rc)
  106. devlink_flash_update_status_notify(devlink, "Flashing success",
  107. header->image_type, 0, 0);
  108. else
  109. devlink_flash_update_status_notify(devlink, "Flashing failed",
  110. header->image_type, 0, 0);
  111. kfree(mdm_rsp);
  112. return rc;
  113. }
  114. /* Call back function for devlink ops */
  115. static const struct devlink_ops devlink_flash_ops = {
  116. .flash_update = ipc_devlink_flash_update,
  117. };
  118. /**
  119. * ipc_devlink_send_cmd - Send command to Modem
  120. * @ipc_devlink: Pointer to struct iosm_devlink
  121. * @cmd: Command to be sent to modem
  122. * @entry: Command entry number
  123. *
  124. * Returns: 0 on success and failure value on error
  125. */
  126. int ipc_devlink_send_cmd(struct iosm_devlink *ipc_devlink, u16 cmd, u32 entry)
  127. {
  128. struct iosm_rpsi_cmd rpsi_cmd;
  129. rpsi_cmd.param.dword = cpu_to_le32(entry);
  130. rpsi_cmd.cmd = cpu_to_le16(cmd);
  131. rpsi_cmd.crc = rpsi_cmd.param.word[0] ^ rpsi_cmd.param.word[1] ^
  132. rpsi_cmd.cmd;
  133. return ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&rpsi_cmd,
  134. sizeof(rpsi_cmd));
  135. }
  136. /* Function to create snapshot */
  137. static int ipc_devlink_coredump_snapshot(struct devlink *dl,
  138. const struct devlink_region_ops *ops,
  139. struct netlink_ext_ack *extack,
  140. u8 **data)
  141. {
  142. struct iosm_devlink *ipc_devlink = devlink_priv(dl);
  143. struct iosm_coredump_file_info *cd_list = ops->priv;
  144. u32 region_size;
  145. int rc;
  146. dev_dbg(ipc_devlink->dev, "Region:%s, ID:%d", ops->name,
  147. cd_list->entry);
  148. region_size = cd_list->default_size;
  149. rc = ipc_coredump_collect(ipc_devlink, data, cd_list->entry,
  150. region_size);
  151. if (rc) {
  152. dev_err(ipc_devlink->dev, "Fail to create snapshot,err %d", rc);
  153. goto coredump_collect_err;
  154. }
  155. /* Send coredump end cmd indicating end of coredump collection */
  156. if (cd_list->entry == (IOSM_NOF_CD_REGION - 1))
  157. ipc_coredump_get_list(ipc_devlink, rpsi_cmd_coredump_end);
  158. return 0;
  159. coredump_collect_err:
  160. ipc_coredump_get_list(ipc_devlink, rpsi_cmd_coredump_end);
  161. return rc;
  162. }
  163. /* To create regions for coredump files */
  164. static int ipc_devlink_create_region(struct iosm_devlink *devlink)
  165. {
  166. struct devlink_region_ops *mdm_coredump;
  167. int rc = 0;
  168. int i;
  169. mdm_coredump = devlink->iosm_devlink_mdm_coredump;
  170. for (i = 0; i < IOSM_NOF_CD_REGION; i++) {
  171. mdm_coredump[i].name = list[i].filename;
  172. mdm_coredump[i].snapshot = ipc_devlink_coredump_snapshot;
  173. mdm_coredump[i].destructor = vfree;
  174. devlink->cd_regions[i] =
  175. devlink_region_create(devlink->devlink_ctx,
  176. &mdm_coredump[i], MAX_SNAPSHOTS,
  177. list[i].default_size);
  178. if (IS_ERR(devlink->cd_regions[i])) {
  179. rc = PTR_ERR(devlink->cd_regions[i]);
  180. dev_err(devlink->dev, "Devlink region fail,err %d", rc);
  181. /* Delete previously created regions */
  182. for (i--; i >= 0; i--)
  183. devlink_region_destroy(devlink->cd_regions[i]);
  184. goto region_create_fail;
  185. }
  186. list[i].entry = i;
  187. mdm_coredump[i].priv = list + i;
  188. }
  189. region_create_fail:
  190. return rc;
  191. }
  192. /* To Destroy devlink regions */
  193. static void ipc_devlink_destroy_region(struct iosm_devlink *ipc_devlink)
  194. {
  195. u8 i;
  196. for (i = 0; i < IOSM_NOF_CD_REGION; i++)
  197. devlink_region_destroy(ipc_devlink->cd_regions[i]);
  198. }
  199. /**
  200. * ipc_devlink_init - Initialize/register devlink to IOSM driver
  201. * @ipc_imem: Pointer to struct iosm_imem
  202. *
  203. * Returns: Pointer to iosm_devlink on success and NULL on failure
  204. */
  205. struct iosm_devlink *ipc_devlink_init(struct iosm_imem *ipc_imem)
  206. {
  207. struct ipc_chnl_cfg chnl_cfg_flash = { 0 };
  208. struct iosm_devlink *ipc_devlink;
  209. struct devlink *devlink_ctx;
  210. int rc;
  211. devlink_ctx = devlink_alloc(&devlink_flash_ops,
  212. sizeof(struct iosm_devlink),
  213. ipc_imem->dev);
  214. if (!devlink_ctx) {
  215. dev_err(ipc_imem->dev, "devlink_alloc failed");
  216. goto devlink_alloc_fail;
  217. }
  218. ipc_devlink = devlink_priv(devlink_ctx);
  219. ipc_devlink->devlink_ctx = devlink_ctx;
  220. ipc_devlink->pcie = ipc_imem->pcie;
  221. ipc_devlink->dev = ipc_imem->dev;
  222. rc = devlink_params_register(devlink_ctx, iosm_devlink_params,
  223. ARRAY_SIZE(iosm_devlink_params));
  224. if (rc) {
  225. dev_err(ipc_devlink->dev,
  226. "devlink_params_register failed. rc %d", rc);
  227. goto param_reg_fail;
  228. }
  229. ipc_devlink->cd_file_info = list;
  230. rc = ipc_devlink_create_region(ipc_devlink);
  231. if (rc) {
  232. dev_err(ipc_devlink->dev, "Devlink Region create failed, rc %d",
  233. rc);
  234. goto region_create_fail;
  235. }
  236. if (ipc_chnl_cfg_get(&chnl_cfg_flash, IPC_MEM_CTRL_CHL_ID_7) < 0)
  237. goto chnl_get_fail;
  238. ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL,
  239. chnl_cfg_flash, IRQ_MOD_OFF);
  240. init_completion(&ipc_devlink->devlink_sio.read_sem);
  241. skb_queue_head_init(&ipc_devlink->devlink_sio.rx_list);
  242. devlink_register(devlink_ctx);
  243. dev_dbg(ipc_devlink->dev, "iosm devlink register success");
  244. return ipc_devlink;
  245. chnl_get_fail:
  246. ipc_devlink_destroy_region(ipc_devlink);
  247. region_create_fail:
  248. devlink_params_unregister(devlink_ctx, iosm_devlink_params,
  249. ARRAY_SIZE(iosm_devlink_params));
  250. param_reg_fail:
  251. devlink_free(devlink_ctx);
  252. devlink_alloc_fail:
  253. return NULL;
  254. }
  255. /**
  256. * ipc_devlink_deinit - To unintialize the devlink from IOSM driver.
  257. * @ipc_devlink: Devlink instance
  258. */
  259. void ipc_devlink_deinit(struct iosm_devlink *ipc_devlink)
  260. {
  261. struct devlink *devlink_ctx = ipc_devlink->devlink_ctx;
  262. devlink_unregister(devlink_ctx);
  263. ipc_devlink_destroy_region(ipc_devlink);
  264. devlink_params_unregister(devlink_ctx, iosm_devlink_params,
  265. ARRAY_SIZE(iosm_devlink_params));
  266. if (ipc_devlink->devlink_sio.devlink_read_pend) {
  267. complete(&ipc_devlink->devlink_sio.read_sem);
  268. complete(&ipc_devlink->devlink_sio.channel->ul_sem);
  269. }
  270. if (!ipc_devlink->devlink_sio.devlink_read_pend)
  271. skb_queue_purge(&ipc_devlink->devlink_sio.rx_list);
  272. ipc_imem_sys_devlink_close(ipc_devlink);
  273. devlink_free(devlink_ctx);
  274. }