PageRenderTime 100ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 1ms

/src/core/mid_statemachine.c

https://gitlab.com/magnusr/modem-init-daemon
C | 2005 lines | 1569 code | 247 blank | 189 comment | 338 complexity | 1907af6e6ed7a4571f44b83629f26add MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (C) 2010 ST-Ericsson AS
  3. * Author: Erwan Bracq / erwan.bracq@stericsson.com
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. * See the NOTICE file distributed with this work for additional
  18. * information regarding copyright ownership.
  19. */
  20. #include <mid_statemachine.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <errno.h>
  25. #include <unistd.h>
  26. #include <private/android_filesystem_config.h>
  27. #include <sys/wait.h>
  28. #include <dlfcn.h>
  29. #include <time.h>
  30. #include <atchannel.h>
  31. #include <mid.h>
  32. #include <mid_caif.h>
  33. #include <mid_error.h>
  34. #include <mid_flash.h>
  35. #include <mid_gpio.h>
  36. #include <mid_ipc.h>
  37. #include <mid_log.h>
  38. #include <mid_mfa.h>
  39. #include <mid_power.h>
  40. #include <crash_dump.h>
  41. #include "mid_dev.h"
  42. #include "mid_sys.h"
  43. #define COUNTOF(A) (sizeof(A)/sizeof((A)[0]))
  44. typedef enum MID_Event_Oper_e {
  45. MID_CLEAR_EVENT,
  46. MID_KEEP_EVENT,
  47. } MID_Event_Oper_t;
  48. typedef MID_Event_Oper_t (*Transition_T)(struct mid * mid_info_p);
  49. typedef struct {
  50. MID_Event_t event;
  51. Transition_T func;
  52. } Event_Func_t;
  53. typedef struct {
  54. Event_Func_t *event_func_info;
  55. int timeout_value;
  56. } State_Entry_t;
  57. static mid_fw_upgr_error_code_t mid_fw_upgr_errors[] = {
  58. {"SYSTEM_ERROR", MID_FW_UPGR_RSLT_SYSTEM_ERROR},
  59. {"INVALID_REQ_PHASE", MID_FW_UPGR_RSLT_INVALID_REQ_PHASE},
  60. {"REQ_IN_PROGRESS", MID_FW_UPGR_RSLT_REQ_IN_PROGRESS},
  61. {"UNSUPP_MODEM", MID_FW_UPGR_RSLT_UNSUPP_MODEM},
  62. {"MODEM_SHUTDOWN", MID_FW_UPGR_RSLT_MODEM_SHUTDOWN},
  63. {"AT_TIMEOUT", MID_FW_UPGR_RSLT_AT_TIMEOUT},
  64. {"REQ_REJECTED", MID_FW_UPGR_RSLT_REJECTED},
  65. {"AT_CHN_ERROR", MID_FW_UPGR_RSLT_AT_CHN_ERROR},
  66. {"AT_CMD_ERROR", MID_FW_UPGR_RSLT_AT_CMD_ERROR},
  67. {"INVALID_MODEM_STATE",MID_FW_UPGR_RSLT_INVALID_MODEM_STATE},
  68. {"FILESYS_ERROR", MID_FW_UPGR_RSLT_FS_ERROR},
  69. {"IMG_SIZE_ERROR", MID_FW_UPGR_RSLT_IMG_SIZE_ERROR},
  70. {"LOW_BATTERY", MID_FW_UPGR_RSLT_LOW_BATT},
  71. {"NO_FW_IMG", MID_FW_UPGR_RSLT_NO_FW_IMG},
  72. };
  73. static const char * const MID_EventNames[] =
  74. {
  75. "MID_IPC_RBT_EVT",
  76. "MID_GPIO_RST2_EVT",
  77. "MID_GPIO_PRST_EVT",
  78. "MID_MODEM_HALT_EVT",
  79. "MID_MODEM_START_EVT",
  80. "MID_SIG_KILL_EVT",
  81. "MID_LONG_OPS_EVT",
  82. "MID_CFRDY_EVT",
  83. "MID_HIGH_TEMPERATURE_EVT",
  84. "MID_LOW_BATTERY_EVT",
  85. "MID_AT_CFUN0_EVT",
  86. "MID_AT_CFUN100_EVT",
  87. "MID_IPC_FW_UPGR_IMG_XFER_EVT",
  88. "MID_IPC_FW_UPGR_FLASH_EVT",
  89. "MID_IPC_FW_UPGR_STATUS_EVT",
  90. "MID_FW_XFER_OPS_EVT",
  91. "MID_FW_XFER_PROGRESS_EVT",
  92. "MID_TIMEOUT_EVT",
  93. "MID_FLASH_START_EVT",
  94. "MID_FLASH_END_EVT",
  95. "MID_LAST_EVT",
  96. };
  97. static const char * const MID_StateNames[] =
  98. {
  99. "STATE_OFF",
  100. "STATE_BOOT",
  101. "STATE_MODINF_UP",
  102. "STATE_ON",
  103. "STATE_DUMP",
  104. "STATE_SHUTDOWN",
  105. "STATE_FLASHING",
  106. };
  107. bool mid_statemachine_get_event_by_name(const char* name, MID_Event_t* event)
  108. {
  109. MID_Event_t i;
  110. for(i=MID_IPC_RBT_EVT; i<=MID_LAST_EVT; i++)
  111. if(strcmp(name, MID_EventNames[i])==0) {
  112. *event=i;
  113. return true;
  114. }
  115. return false;
  116. }
  117. // Helper functions
  118. static inline void lock_mid_data(struct mid* mid_info)
  119. {
  120. apr_status_t status;
  121. if (unlikely((status = apr_thread_mutex_lock(mid_info->mutex)) != APR_SUCCESS)) {
  122. char message[100];
  123. MLGE("MID: MID Unable to take internal mid data mutex: %s",
  124. apr_strerror(status, message, sizeof(message)));
  125. }
  126. }
  127. static inline void unlock_mid_data(struct mid* mid_info)
  128. {
  129. apr_status_t status;
  130. if (unlikely((status = apr_thread_mutex_unlock(mid_info->mutex)) != APR_SUCCESS)) {
  131. char message[100];
  132. MLGE("MID: MID Unable to release internal mid data mutex: %s",
  133. apr_strerror(status, message, sizeof(message)));
  134. }
  135. }
  136. #define LOCK_MID_DATA lock_mid_data(mid_info)
  137. #define UNLOCK_MID_DATA unlock_mid_data(mid_info)
  138. static char * mid_fw_upgrade_get_error_str(struct mid* mid_info, int error_code)
  139. {
  140. char * ret = NULL;
  141. int i;
  142. unsigned char num_codes
  143. = sizeof(mid_fw_upgr_errors) / sizeof(mid_fw_upgr_error_code_t);
  144. for (i = 0; i < num_codes; i++) {
  145. if (mid_fw_upgr_errors[i].error_code == error_code)
  146. break;
  147. }
  148. if (i < num_codes)
  149. ret = mid_fw_upgr_errors[i].str;
  150. else
  151. ret = mid_info->moli_fw_upgr_get_error_str(mid_info, error_code);
  152. return ret;
  153. }
  154. static const char* get_reason_from_last_event(struct mid* mid_info)
  155. {
  156. switch(mid_info->cur_event) {
  157. case MID_IPC_RBT_EVT: return "ipc";
  158. case MID_GPIO_RST2_EVT: return "rst2";
  159. case MID_GPIO_PRST_EVT: return "prst";
  160. case MID_MODEM_HALT_EVT: return "modem_halt";
  161. case MID_MODEM_START_EVT: return "modem_start";
  162. case MID_SIG_KILL_EVT: return "kill";
  163. case MID_LONG_OPS_EVT: return "long_op";
  164. case MID_CFRDY_EVT: return "caif_ready";
  165. case MID_HIGH_TEMPERATURE_EVT: return "temp";
  166. case MID_LOW_BATTERY_EVT: return "battery";
  167. case MID_AT_CFUN0_EVT: return "cfun=0";
  168. case MID_AT_CFUN100_EVT: return "cfun=100";
  169. case MID_IPC_FW_UPGR_IMG_XFER_EVT: return "fw_upgrade_xfer";
  170. case MID_IPC_FW_UPGR_FLASH_EVT: return "fw_upgrade_flash";
  171. case MID_IPC_FW_UPGR_STATUS_EVT: return "fw_upgrade_status";
  172. case MID_FW_XFER_OPS_EVT: return "fw_upgrade_op";
  173. case MID_FW_XFER_PROGRESS_EVT: return "fw_upgrade_progress";
  174. case MID_TIMEOUT_EVT: return "timeout";
  175. case MID_FLASH_START_EVT: return "flash_start";
  176. case MID_FLASH_END_EVT: return "flash_end";
  177. case MID_LAST_EVT:
  178. default: return "[unknown]";
  179. }
  180. }
  181. static int state_all_act_shutdown(struct mid* mid_info, int sendCfun)
  182. {
  183. int res = 0;
  184. union ipc_msg msg;
  185. ATResponse *atresponse = NULL;
  186. MLGD("STMACH: MID execute Action: Shutdown.");
  187. /* Notify other AT client that a shutdown is nearby. */
  188. ipc_prepare_message(&msg, STATECHANGE, "prepare_off", get_reason_from_last_event(mid_info));
  189. ipc_send_message(msg);
  190. MLGD("STMACH: MID sent prepare_off message. A modem shutdown is coming.");
  191. /* Special case - no PWRRSTIN available, we can use RESOUT2 to check if modem is alive under specific conditions. */
  192. if (unlikely(!mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2) && mid_gpio_used(mid_info->gpios, GPIO_ID_RESOUT2) && !mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN))) {
  193. if (!mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN) && mid_info->modem_is_on == 0) {
  194. MLGD("MID: Modem is already down according GPIO RESOUT2 level - MID will now cut power.");
  195. goto modem_already_off;
  196. }
  197. }
  198. /* Normal case - PWRRSTIN is used to check if modem is on or off. */
  199. if (unlikely(!mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN) && mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN))) {
  200. MLGD("MID: Modem is already down according GPIO PWRRSTIN level - MID will now cut power.");
  201. goto modem_already_off;
  202. }
  203. /* If AT channel is available. Use it to power down with AT+CFUN commands. */
  204. if ((mid_info->at_chnl_fd >= 0) && (sendCfun)) {
  205. int *fd = &(mid_info->at_chnl_fd);
  206. int written = 0;
  207. MLGD("MID: AT channel available. Try to shutdown with AT commands.");
  208. /* Case where we got a AT+CFUN=0 requested on another AT channel. A modem reboot is trigged. */
  209. if (FLAG_UP(mid_info->event, MID_AT_CFUN0_EVT) &&
  210. mid_info->config->enable_efwd_atcfun) {
  211. /* Send OK response to command CFUN=0 on other channel. */
  212. MLGD("AT: >>> Forward command reply for CFUN=: %s", mid_info->at_cfun0_resp);
  213. written = write(*fd, mid_info->at_cfun0_resp, strlen(mid_info->at_cfun0_resp));
  214. if (written != (int)strlen(mid_info->at_cfun0_resp)) {
  215. MLGW("AT: >>> Failure on AT+CFUN forwarded command.");
  216. }
  217. free(mid_info->at_cfun0_resp);
  218. /* Toggle a reboot event */
  219. MLGD("STMACH: MID_IPC_RBT_EVT event set");
  220. SET_FLAG(mid_info->event, MID_IPC_RBT_EVT);
  221. }
  222. /* Case for AT+CFUN=100 enabled modem. */
  223. if (mid_info->prep_for_shutdown) {
  224. /* AT+CFUN=100 is done if we use a OnSwC modem or flashless configuration. */
  225. if (mid_info->config->use_on_sw_c || mid_info->config->initial_enable_bootldr) {
  226. MLGD("AT: >>> Execute AT+CFUN=100.");
  227. res = at_send_command("AT+CFUN=100", &atresponse);
  228. if (res < 0 || atresponse->success == 0) {
  229. MLGW("AT: >>> Failure on AT+CFUN command.");
  230. }
  231. at_response_free(atresponse);
  232. }
  233. /* Case where we got a AT+CFUN=100 requested on another AT channel. */
  234. if (FLAG_UP(mid_info->event, MID_AT_CFUN100_EVT) &&
  235. mid_info->config->enable_efwd_atcfun) {
  236. /* Send OK response to command CFUN=100 on other channel. */
  237. MLGD("AT: >>> Forward command reply for CFUN=: %s", mid_info->at_cfun100_resp);
  238. written = write(*fd, mid_info->at_cfun100_resp, strlen(mid_info->at_cfun100_resp));
  239. if (written != (int)strlen(mid_info->at_cfun100_resp)) {
  240. MLGW("AT: >>> Failure on AT+CFUN forwarded command.");
  241. }
  242. free(mid_info->at_cfun100_resp);
  243. }
  244. /* If we force it, AT+CFUN=0 is used to shutdown. Typical case is OnSwA modem. */
  245. if (mid_info->config->use_atcfun0) {
  246. MLGD("AT: >>> Execute AT+CFUN=0.");
  247. res = at_send_command("AT+CFUN=0", &atresponse);
  248. if (res < 0 || atresponse->success == 0) {
  249. MLGW("AT: >>> Failure on AT+CFUN command.");
  250. }
  251. at_response_free(atresponse);
  252. }
  253. } else {
  254. /* Case for non AT+CFUN=100 enabled modem. */
  255. MLGD("AT: >>> Execute AT+CFUN=0.");
  256. res = at_send_command("AT+CFUN=0", &atresponse);
  257. if (res < 0 || atresponse->success == 0) {
  258. MLGW("AT: >>> Failure on AT+CFUN command.");
  259. }
  260. at_response_free(atresponse);
  261. }
  262. } else {
  263. /* Modem is on, but we don t have AT channel, so we need to force power off via GPIO */
  264. res = 1;
  265. }
  266. modem_already_off:
  267. if ((mid_info->config->enable_at_channel) && (mid_info->at_chnl_fd >= 0))
  268. mid_at_chnl_close(mid_info);
  269. return res;
  270. }
  271. int state_all_evt_sig_kill(struct mid* mid_info)
  272. {
  273. int res = 0;
  274. apr_status_t status;
  275. MLGD("STMACH: MID execute Action: SIG_KILL processing.");
  276. CLEAR_FLAG(mid_info->event, MID_SIG_KILL_EVT);
  277. MLGD("STMACH: MID_SIG_KILL_EVT event cleared.");
  278. if (mid_info->config->enable_at_channel && (mid_info->at_chnl_fd >= 0))
  279. mid_at_chnl_close(mid_info);
  280. mid_enable_gpio_out_safe_mode(mid_info);
  281. if(mid_info->gpios) mid_gpio_release_all(mid_info->gpios);
  282. /* Disconnect IPC */
  283. res = ipc_medium_disconnect();
  284. if (unlikely(res != 0))
  285. MLGE("MID: Unable to stop IPC");
  286. #ifdef DEBUG_TRACE
  287. if (unlikely(mid_dbg_info.log_fd != NULL)) {
  288. res = fclose(mid_dbg_info.log_fd);
  289. mid_dbg_info.log_fd = NULL;
  290. if (res)
  291. MLGE("MID: Unable to close LOG file");
  292. }
  293. #endif
  294. /* TODO check how to clean up - If used by config, after a destroy, the value is not 0 or NULL
  295. if used by command line, a malloc is done
  296. if (mid_info->cfgfile != NULL)
  297. free(mid_info->cfgfile);
  298. if (mid_info->rdir != NULL)
  299. free(mid_info->rdir);
  300. */
  301. if (mid_info->dl_handle != NULL)
  302. dlclose(mid_info->dl_handle);
  303. /* Clean up everything */
  304. status = apr_thread_mutex_destroy(mid_info->mutex);
  305. if (unlikely(status != APR_SUCCESS)) {
  306. char message[100];
  307. MLGE("MID: Unable to destroy internal mid data mutex: %s",
  308. apr_strerror(status, message, sizeof(message)));
  309. }
  310. MLGD("MID: MID ended.");
  311. exit(EXIT_SUCCESS);
  312. }
  313. static int modem_power_off(struct mid* mid_info)
  314. {
  315. int res = 0;
  316. MLGD("STMACH: MID execute power OFF sequence");
  317. /* Have to put IO in safe mode before power off in order to prevent leakage */
  318. mid_enable_io_safe_mode(mid_info);
  319. if (mid_info->config->use_on_sw_c) {
  320. /* OnSwC */
  321. MLGD("GPIO: Using OnSwC");
  322. MLGD("GPIO: De-assert MOD ON pin");
  323. res = mid_gpio_deassert(mid_info->gpios, GPIO_ID_ON);
  324. if (unlikely(res)) {
  325. MLGE("GPIO: Can't deassert GPIO_ON");
  326. return -EMIDGPIO;
  327. }
  328. } else {
  329. /* OnSwA */
  330. MLGD("GPIO: Using OnSwA");
  331. MLGD("GPIO: Assert MOD ON pin");
  332. res = mid_gpio_assert(mid_info->gpios, GPIO_ID_ON);
  333. if (unlikely(res)) {
  334. MLGE("GPIO: Can't assert GPIO_ON");
  335. return -EMIDGPIO;
  336. }
  337. MLGD("GPIO: OnSwa long assert: %d seconds.", MODEM_POWER_OFF_LAT);
  338. sleep(MODEM_POWER_OFF_LAT);
  339. MLGD("GPIO: De-assert MOD ON pin");
  340. res = mid_gpio_deassert(mid_info->gpios, GPIO_ID_ON);
  341. if (unlikely(res)) {
  342. MLGE("GPIO: Can't deassert GPIO_ON");
  343. return -EMIDGPIO;
  344. }
  345. }
  346. MLGD("GPIO: De-assert PWRRSTOUT pin");
  347. usleep(2000);
  348. if (unlikely(mid_gpio_deassert(mid_info->gpios, GPIO_ID_PWRRSTOUT))) {
  349. MLGE("GPIO: Can't deassert GPIO_PWRRSTOUT");
  350. return -EMIDGPIO;
  351. }
  352. MLGD("STMACH: MID will be idle for 50 millisecond to allow safe mode propagation on IOs.");
  353. usleep(50000);
  354. return 0;
  355. }
  356. void shutdown_modem(struct mid* mid_info)
  357. {
  358. int ko_shutdown_result = 0;
  359. ssize_t maxwaittime = 100; /* Number of iteration in 50msec unit. Total is 50*100 = 5 sec */
  360. ssize_t reloadmaxwaittime = 20; /* Releoad timeout for 1 second on wrong shutdown operation */
  361. union ipc_msg msg;
  362. MLGD("STMACH: MID execute shutdown modem sequence");
  363. /* Signal all utility threads to shut down */
  364. mid_info->kill_threads = 1;
  365. /* Shutdown during fw upgrade flashing */
  366. /* If we fore some reason hasn't answered the IPCDB request for flashing we send a response now. */
  367. if (mid_info->fw_upgr_flash_reply_msg) {
  368. const char *errorstr = mid_fw_upgrade_get_error_str(mid_info,mid_info->fw_upgr_last_error);
  369. if (ipc_send_async_reply(&mid_info->fw_upgr_flash_reply_msg,
  370. (errorstr ? errorstr : "ERROR")))
  371. MLGE("MID: Failed to send fw upgrade error reply");
  372. }
  373. ko_shutdown_result = state_all_act_shutdown(mid_info, 1);
  374. /* After this point, AT channel is closed or not available */
  375. if (ko_shutdown_result)
  376. MLGW("MID: AT command not available to shutdown. Modem will be killed via GPIO control.");
  377. /* Time to execute Off command. If we do this after powering off we will have leakage. */
  378. MLGD("Cleaning up drivers before powering off in order to prevent leakage when power off modem");
  379. (void)my_system(mid_info, mid_info->config->mod_off_cmd);
  380. /* Power off the modem via ONSWa or ONSWc now */
  381. /* To poweroff the following condition should apply :
  382. * - GPIO RESOUT2 or GPIO PWRRSTIN used and high
  383. * - Prepare for shutdown enabled modem (AT+CFUN=100) and no forced AT+CFUN=0 shutdown command
  384. * OR
  385. * - Error on AT commands (ko_shutdown_result condition)
  386. *
  387. * For forced AT+CFUN=0 shutdown command (use_atcfun=0 condition) or "non prepare for shutdown" enabled modem
  388. * the standard way to shutdown is AT+CFUN=0. The modem will turn off by itself.
  389. */
  390. if (((mid_info->prep_for_shutdown && !mid_info->config->use_atcfun0) || ko_shutdown_result)
  391. && ((mid_gpio_used(mid_info->gpios, GPIO_ID_RESOUT2) && mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2))
  392. || (mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN) && mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN))))
  393. if (modem_power_off(mid_info))
  394. MLGE("STMACH: Trouble in power off sequence. Modem may not be switched Off.");
  395. /* Last paranoiac check - PWRRSTIN & RESOUT2 should be low for prepare_for_shutdown enabled modem */
  396. if (unlikely(mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2) || mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN))) {
  397. /* If they don't MID will report error */
  398. if (mid_info->prep_for_shutdown && !mid_info->config->use_atcfun0) {
  399. if (mid_info->config->modem_arch_id == OSMIUM) {
  400. /* An insane case, DBB is powered off but ABB not. */
  401. if (!(mid_gpio_used(mid_info->gpios, GPIO_ID_RESET) && (mid_gpio_assert(mid_info->gpios, GPIO_ID_RESET)))) {
  402. MLGE("STMACH: Modem is not powered off after GPIO_RESET sequence. This is a MODEM bug - MID will be out of sync.");
  403. #if defined(MOTOROLA_FEATURE)
  404. mid_statemachine_log_panic_apr("Subtype: Modem is not powered off after GPIO_RESET sequence.\n", mid_info->config->critical_panic_detection_file);
  405. #endif
  406. mid_platform_reboot(mid_info);
  407. }
  408. }
  409. else {
  410. MLGE("STMACH: Modem is not powered off after GPIO_ON sequence. This is a MODEM bug - MID will be out of sync.");
  411. #if defined(MOTOROLA_FEATURE)
  412. mid_statemachine_log_panic_apr("Subtype: Modem is not powered off after GPIO_ON sequence.\n", mid_info->config->critical_panic_detection_file);
  413. #endif
  414. mid_platform_reboot(mid_info);
  415. }
  416. }
  417. }
  418. /* Special case to call a GPIO forced power off */
  419. if (mid_info->config->force_gpio_pwroff)
  420. modem_power_off(mid_info);
  421. /* Active loop to wait modem shutdown completion. Modem should be already off here, except if AT+CFUN=0 command is used with success
  422. * Then we let 5 sec to modem to complete power down.
  423. */
  424. while ((mid_gpio_used(mid_info->gpios, GPIO_ID_RESOUT2) && mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2))
  425. || (mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN) && mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN))) {
  426. /* Sleep 50 milliseconds */
  427. usleep(50000); /* Poll every 50msec */
  428. maxwaittime--;
  429. if (maxwaittime == 0) {
  430. MLGE("STMACH: Modem shutdown timeout.");
  431. if (mid_info->config->modem_arch_id == OSMIUM) {
  432. /* An insane case, DBB is powered off but ABB not. */
  433. if (!(mid_gpio_used(mid_info->gpios, GPIO_ID_RESET) && (mid_gpio_assert(mid_info->gpios, GPIO_ID_RESET)))) {
  434. MLGE("STMACH: Modem is not powered off after GPIO_RESET sequence. This is a MODEM bug - MID will be out of sync.");
  435. MLGE("GPIO: GPIO_ID_RESOUT2 STATUS :%d", mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2));
  436. MLGE("GPIO: GPIO_ID_PWRRSTIN STATUS :%d", mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN));
  437. #if defined(MOTOROLA_FEATURE)
  438. mid_statemachine_log_panic_apr("Subtype: Modem is not powered off after GPIO_RESET sequence and shutdown timeout.\n", mid_info->config->critical_panic_detection_file);
  439. #endif
  440. mid_platform_reboot(mid_info);
  441. }
  442. if (reloadmaxwaittime) {
  443. maxwaittime = reloadmaxwaittime;
  444. reloadmaxwaittime = 0;
  445. }
  446. else {
  447. MLGE("STMACH: MID is NOW out of sync. MID is in STATE_OFF BUT modem is in Zombie state.");
  448. MLGE("GPIO: GPIO_ID_RESOUT2 STATUS :%d", mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2));
  449. MLGE("GPIO: GPIO_ID_PWRRSTIN STATUS :%d", mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN));
  450. /* Unrecoverable case: This will trig a platform reboot or a MID spin loop. */
  451. #if defined(MOTOROLA_FEATURE)
  452. mid_statemachine_log_panic_apr("Subtype: MID is NOW out of sync. MID is in STATE_OFF BUT modem is in Zombie state after shutdown timeout.\n", mid_info->config->critical_panic_detection_file);
  453. #endif
  454. mid_platform_reboot(mid_info);
  455. }
  456. }
  457. else {
  458. MLGE("STMACH: MID is NOW out of sync. MID is in STATE_OFF BUT modem is in Zombie state.");
  459. MLGE("GPIO: GPIO_ID_RESOUT2 STATUS :%d", mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2));
  460. MLGE("GPIO: GPIO_ID_PWRRSTIN STATUS :%d", mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN));
  461. if (!mid_info->shutdown_retry_left) {
  462. /* Unrecoverable case: This will trig a platform reboot or a MID spin loop. */
  463. #if defined(MOTOROLA_FEATURE)
  464. mid_statemachine_log_panic_apr("Subtype: MID is NOW out of sync. MID is in STATE_OFF BUT modem is in Zombie state after shutdown timeout.\n", mid_info->config->critical_panic_detection_file);
  465. #endif
  466. mid_platform_reboot(mid_info);
  467. } else {
  468. /* On rare occasions this can be recoverable... */
  469. mid_info->shutdown_retry_left--;
  470. return;
  471. }
  472. }
  473. }
  474. }
  475. /* OSMIUM special case, deassert GPIO_ID_RESET if used. */
  476. if (mid_info->config->modem_arch_id == OSMIUM && mid_gpio_used(mid_info->gpios, GPIO_ID_RESET) && mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESET))
  477. mid_gpio_deassert(mid_info->gpios, GPIO_ID_RESET);
  478. MLGD("STMACH: Modem is now off.");
  479. if (mid_info->ipc_reboot_received) {
  480. mid_info->ipc_reboot_received = 0;
  481. #if defined(MOTOROLA_FEATURE)
  482. mid_statemachine_log_panic_apr("Subtype: Modem IPC failure, no system reboot.\n", mid_info->config->silent_panic_detection_file);
  483. #endif
  484. }
  485. ipc_prepare_message(&msg, STATECHANGE, "off", get_reason_from_last_event(mid_info));
  486. ipc_send_message(msg);
  487. mid_info->state = STATE_OFF;
  488. mid_info->shutdown_retry_left = mid_info->config->shutdown_retry;
  489. }
  490. static int modem_power_on(struct mid* mid_info, int disable_io_safe_mode)
  491. {
  492. int res = 0;
  493. MLGD("STMACH: MID execute power on sequence");
  494. #if !defined(MOTOROLA_FEATURE)
  495. if (disable_io_safe_mode)
  496. #endif
  497. mid_disable_io_safe_mode(mid_info);
  498. MLGD("GPIO: Assert PWRRSTOUT pin");
  499. if (unlikely(mid_gpio_assert(mid_info->gpios, GPIO_ID_PWRRSTOUT))) {
  500. MLGE("GPIO: Can't assert GPIO_PWRRSTOUT");
  501. mid_enable_io_safe_mode(mid_info);
  502. return -EMIDGPIO;
  503. }
  504. usleep(2000);
  505. if (mid_info->config->use_on_sw_c) {
  506. /* OnSwC */
  507. MLGD("GPIO: Using OnSwC");
  508. MLGD("GPIO: Assert MOD ON pin");
  509. res = mid_gpio_assert(mid_info->gpios, GPIO_ID_ON);
  510. if (unlikely(res)) {
  511. MLGE("GPIO: Can't assert GPIO_ON");
  512. mid_enable_io_safe_mode(mid_info);
  513. return -EMIDGPIO;
  514. }
  515. if (!mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN))
  516. mid_info->modem_is_on = 1;
  517. return 0;
  518. }
  519. /* OnSwA */
  520. MLGD("GPIO: Using OnSwA");
  521. MLGD("GPIO: Assert MOD ON pin");
  522. res = mid_gpio_assert(mid_info->gpios, GPIO_ID_ON);
  523. if (unlikely(res)) {
  524. MLGE("GPIO: Can't assert GPIO_ON");
  525. mid_enable_io_safe_mode(mid_info);
  526. return -EMIDGPIO;
  527. }
  528. mid_info->power_on_release = 1;
  529. if ((!isdirempty(mid_info->config->initial_rdir) && (!mid_info->config->initial_enable_bootldr)) || !mid_gpio_used(mid_info->gpios, GPIO_ID_RESOUT2)) {
  530. /* This is for:
  531. * - non RESOUT2 enabled hardware
  532. * - flashed configuration when modem has to be flashed - No RESOUT2 are available from loaders */
  533. MLGD("GPIO: OnSwa long assert: %d seconds.", MODEM_POWER_ON_LAT);
  534. sleep(MODEM_POWER_ON_LAT);
  535. MLGD("GPIO: De-assert MOD ON pin");
  536. res = mid_gpio_deassert(mid_info->gpios, GPIO_ID_ON);
  537. if (unlikely(res)) {
  538. MLGE("GPIO: Can't deassert GPIO_ON");
  539. mid_info->power_on_release = 0;
  540. mid_enable_io_safe_mode(mid_info);
  541. return -EMIDGPIO;
  542. }
  543. mid_info->power_on_release = 0;
  544. }
  545. if (!mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN))
  546. mid_info->modem_is_on = 1;
  547. return 0;
  548. }
  549. // Helper thread procedures
  550. struct delayed_dump_args {
  551. struct mid* mid_info;
  552. unsigned int seconds;
  553. };
  554. static void *delayed_dump(apr_thread_t* thread, void *arg)
  555. {
  556. UNUSED(thread);
  557. struct delayed_dump_args* args=arg;
  558. MLGD("STMACH: MID execute delayed dump sequence, with %d seconds delay", args->seconds);
  559. sleep(args->seconds);
  560. SET_FLAG(args->mid_info->event, MID_GPIO_RST2_EVT);
  561. MLGD("STMACH: MID_GPIO_RST2_EVT event set.");
  562. free(args);
  563. return NULL;
  564. }
  565. static int start_delayed_dump(apr_thread_t** thread, struct mid* mid_info, unsigned int seconds)
  566. {
  567. struct delayed_dump_args* args=malloc(sizeof(struct delayed_dump_args));
  568. args->mid_info=mid_info;
  569. args->seconds=seconds;
  570. return apr_thread_create(thread, NULL, delayed_dump, args, mid_info->pool);
  571. }
  572. static void *rfm_sleep(apr_thread_t* thread, void *arg)
  573. {
  574. UNUSED(thread);
  575. struct mid* mid_info=arg;
  576. int timetosleep = mid_info->config->rfm_delay;
  577. UNUSED(arg);
  578. MLGD("STMACH: SIMULATED MID_CFRDY_EVT (with a sleep command with sleep delay: %d) \n", timetosleep);
  579. if (mid_info->config->initial_sec_data_conf == 1) {
  580. /* Sanity delay to let enough time for a non prepared hardware */
  581. timetosleep = 10;
  582. }
  583. sleep(timetosleep);
  584. if (mid_info->config->enable_at_channel) {
  585. if (mid_at_chnl_open(mid_info)) {
  586. MLGE("MID: Unable to open AT channel. Modem will be shutdown.");
  587. shutdown_modem(mid_info);
  588. return 0;
  589. }
  590. /* Response for oppening the AT channel will generated the CFRDY event */
  591. return 0;
  592. }
  593. /* Since we don't open the AT channel we must generate the CFRDY event here */
  594. SET_FLAG(mid_info->event, MID_CFRDY_EVT);
  595. MLGD("STMACH: MID_CFRDY_EVT event set.");
  596. return 0;
  597. }
  598. /***************
  599. ANY
  600. ***************/
  601. MID_Event_Oper_t MID_State_Any__Event_GPIO_PRST_EVT(struct mid *mid_info)
  602. {
  603. union ipc_msg msg;
  604. MLGD("STMACH: MID execute Action: GPIO_PRST_EVT processing.");
  605. if (mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN)) {
  606. MLGW("STMACH: Modem GPIO PWRRSTIN event, and GPIO level is high. This means modem is powered.");
  607. return MID_CLEAR_EVENT;
  608. }
  609. MLGW("STMACH: Modem unexpected powered off according GPIO PWRRSTIN.");
  610. (void)my_system(mid_info, mid_info->config->mod_off_cmd);
  611. ipc_prepare_message(&msg, STATECHANGE, "off", get_reason_from_last_event(mid_info));
  612. ipc_send_message(msg);
  613. mid_info->state = STATE_OFF;
  614. return MID_CLEAR_EVENT;
  615. }
  616. MID_Event_Oper_t MID_State_Any__Event_HIGH_TEMPERATURE_EVT(struct mid *mid_info)
  617. {
  618. MLGD("STMACH: MID execute Action: HIGH_TEMPERATURE_EVT processing.");
  619. shutdown_modem(mid_info);
  620. return MID_CLEAR_EVENT;
  621. }
  622. MID_Event_Oper_t MID_State_Any__Event_LOW_BATTERY_EVT(struct mid *mid_info)
  623. {
  624. MLGD("STMACH: MID execute Action: LOW_BATTERY_EVT processing.");
  625. shutdown_modem(mid_info);
  626. return MID_CLEAR_EVENT;
  627. }
  628. MID_Event_Oper_t UnExpected_Event(struct mid *mid_info)
  629. {
  630. MLGE("STMACH: MID received event:%s in state:%s. This event will not be handled and cleared because it s a out of sync event.", MID_EventNames[mid_info->cur_event],MID_StateNames[mid_info->state]);
  631. return MID_CLEAR_EVENT;
  632. }
  633. MID_Event_Oper_t Save_Event(struct mid *mid_info_p)
  634. {
  635. UNUSED(mid_info_p);
  636. return MID_KEEP_EVENT;
  637. }
  638. MID_Event_Oper_t MID_State_Any__Event_SIG_KILL(struct mid *mid_info)
  639. {
  640. MLGD("STMACH: MID execute Action: SIG_KILL processing.");
  641. shutdown_modem(mid_info);
  642. return MID_KEEP_EVENT;
  643. }
  644. MID_Event_Oper_t UnExpected_Async_Event(struct mid *mid_info)
  645. {
  646. MLGE("STMACH: MID received event:%s in state:%s. This event will not be handled and cleared because it s a out of sync event.", MID_EventNames[mid_info->cur_event],MID_StateNames[mid_info->state]);
  647. return MID_CLEAR_EVENT;
  648. }
  649. MID_Event_Oper_t MID_State_Any__Event_FW_XFER_OPS(struct mid *mid_info)
  650. {
  651. const char * errorstr = NULL;
  652. MLGD("STMACH: MID execute Action: FW_XFER_OPS_EVT processing.");
  653. MLGD("STMACH: MID_State_Any__Event_FW_XFER_OPS - result is %d", mid_info->fw_xfer_result);
  654. /* Handler for fw xfer thread status event */
  655. if (mid_info->fw_xfer_result == MID_FW_XFER_OK) {
  656. MLGD("MID: MID_State_Any__Event_FW_XFER_OPS: Got OK"); //DBG
  657. if (ipc_send_async_reply(&mid_info->fw_upgr_img_xfer_reply_msg, "OK")) {
  658. MLGE("DBUS: MID_State_Any__Event_FW_XFER_OPS: Failed to send reply");
  659. }
  660. } else {
  661. MLGD("MID: MID_State_Any__Event_FW_XFER_OPS: Got ERROR"); //DBG
  662. errorstr = mid_fw_upgrade_get_error_str(mid_info, mid_info->fw_upgr_last_error);
  663. if (ipc_send_async_reply(&mid_info->fw_upgr_img_xfer_reply_msg,
  664. (errorstr ? errorstr : "ERROR"))) {
  665. MLGE("DBUS: MID_State_Any__Event_FW_XFER_OPS: Failed to send reply");
  666. }
  667. }
  668. return MID_CLEAR_EVENT;
  669. }
  670. MID_Event_Oper_t MID_State_Any__Event_FW_UPGR(struct mid *mid_info)
  671. {
  672. const char * error = NULL;
  673. MLGD("STMACH: MID execute Action: FW_UPGR_EVT processing.");
  674. switch (mid_info->cur_event) {
  675. case MID_IPC_FW_UPGR_IMG_XFER_EVT:
  676. if (mid_info->fw_upgr_img_xfer_reply_msg != NULL) {
  677. error = mid_fw_upgrade_get_error_str(mid_info, MID_FW_UPGR_RSLT_REJECTED);
  678. if (ipc_send_async_reply(&mid_info->fw_upgr_img_xfer_reply_msg,
  679. (error ? error : "REJECTED"))) {
  680. MLGE("DBUS: UnExpected_Async_Event: Failed to send reply");
  681. }
  682. }
  683. break;
  684. case MID_IPC_FW_UPGR_FLASH_EVT:
  685. if (mid_info->fw_upgr_flash_reply_msg != NULL) {
  686. error = mid_fw_upgrade_get_error_str(mid_info, MID_FW_UPGR_RSLT_REJECTED);
  687. if (ipc_send_async_reply(&mid_info->fw_upgr_flash_reply_msg,
  688. (error ? error : "REJECTED"))) {
  689. MLGE("DBUS: UnExpected_Async_Event: Failed to send reply");
  690. }
  691. }
  692. break;
  693. case MID_IPC_FW_UPGR_STATUS_EVT:
  694. if (mid_info->fw_upgr_status_reply_msg != NULL) {
  695. error = mid_fw_upgrade_get_error_str(mid_info, MID_FW_UPGR_RSLT_REJECTED);
  696. if (ipc_send_async_reply(&mid_info->fw_upgr_status_reply_msg,
  697. (error ? error : "REJECTED"))) {
  698. MLGE("DBUS: UnExpected_Async_Event: Failed to send reply");
  699. }
  700. }
  701. break;
  702. case MID_IPC_RBT_EVT: /* Fall though */
  703. case MID_GPIO_RST2_EVT: /* Fall though */
  704. case MID_GPIO_PRST_EVT: /* Fall though */
  705. case MID_MODEM_HALT_EVT: /* Fall though */
  706. case MID_MODEM_START_EVT: /* Fall though */
  707. case MID_SIG_KILL_EVT: /* Fall though */
  708. case MID_LONG_OPS_EVT: /* Fall though */
  709. case MID_CFRDY_EVT: /* Fall though */
  710. case MID_HIGH_TEMPERATURE_EVT: /* Fall though */
  711. case MID_LOW_BATTERY_EVT: /* Fall though */
  712. case MID_AT_CFUN0_EVT: /* Fall though */
  713. case MID_AT_CFUN100_EVT: /* Fall though */
  714. case MID_FW_XFER_OPS_EVT: /* Fall though */
  715. case MID_FW_XFER_PROGRESS_EVT: /* Fall though */
  716. case MID_TIMEOUT_EVT: /* Fall though */
  717. case MID_FLASH_START_EVT: /* Fall though */
  718. case MID_FLASH_END_EVT: /* Fall though */
  719. case MID_LAST_EVT: /* Fall though */
  720. default:
  721. MLGE("STMACH: Current event(%s) doesn't match any firmware upgrade event!",MID_EventNames[mid_info->cur_event]);
  722. break;
  723. }
  724. return MID_CLEAR_EVENT;
  725. }
  726. MID_Event_Oper_t MID_State_Any__Event_TIMEOUT(struct mid *mid_info)
  727. {
  728. MLGD("STMACH: MID execute Action: TIMEOUT_EVT processing.");
  729. MLGW("STMACH: Shutting down modem due to timeout in a transient state");
  730. /* If none of the two events below is set we need to set these in */
  731. /* order to reboot after shutting down modem */
  732. if (!FLAG_UP(mid_info->event, MID_MODEM_START_EVT) && !FLAG_UP(mid_info->event, MID_IPC_RBT_EVT)) {
  733. SET_FLAG(mid_info->event, MID_MODEM_START_EVT);
  734. MLGD("STMACH: MID_MODEM_START_EVT event set.");
  735. }
  736. /* Special care when we are in ModInfUp state and when we don t receive EMRDY from modem. AT channel could be non-responsive
  737. * So AT is closed here to prevent shutdown hanging */
  738. if (mid_info->state == STATE_MODINF_UP)
  739. mid_at_chnl_close(mid_info);
  740. shutdown_modem(mid_info);
  741. return MID_CLEAR_EVENT;
  742. }
  743. /***************
  744. FLASHING
  745. ***************/
  746. static MID_Event_Oper_t MID_State_Flashing__Event_GPIO_PRST(struct mid *mid_info)
  747. {
  748. if (mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN) == 0) {
  749. MLGD("Ingnoring PWRRSTIN going low during flashing");
  750. return MID_CLEAR_EVENT;
  751. }
  752. mid_disable_tx_safe_mode(mid_info);
  753. mid_mfa_notify_on(mid_info->mfa);
  754. return MID_CLEAR_EVENT;
  755. }
  756. static MID_Event_Oper_t MID_State_Flashing__Event_FLASH_START(struct mid *mid_info)
  757. {
  758. if (modem_power_on(mid_info, 1) != 0) {
  759. MLGE("MFA: Failed to power up the modem");
  760. mid_mfa_stop(mid_info->mfa, false);
  761. SET_FLAG(mid_info->event, MID_FLASH_END_EVT);
  762. }
  763. return MID_CLEAR_EVENT;
  764. }
  765. static MID_Event_Oper_t mid_statemachine_try_boot(struct mid *mid_info)
  766. {
  767. union ipc_msg msg;
  768. #if defined(MOTOROLA_FEATURE)
  769. if (mot_mid_info.dual_boot_mode)
  770. mid_info->boot_retry_left = mid_info->config->boot_retry;
  771. #endif
  772. /* FLASHED VARIANT - POWER UP MODEM */
  773. MLGD("MID: MID power up the modem started (Retries left:%d)",mid_info->boot_retry_left);
  774. if (mid_info->boot_retry_left == 0 && !mid_info->boot_failed) {
  775. if (mid_info->config->reboot_on_failure)
  776. #if defined(MOTOROLA_FEATURE)
  777. {
  778. mid_statemachine_log_panic_apr("Subtype: MID bootloader: maximum number of retries reached.\n", mid_info->config->critical_panic_detection_file);
  779. #endif
  780. mid_platform_reboot(mid_info);
  781. #if defined(MOTOROLA_FEATURE)
  782. }
  783. #endif
  784. MLGD("MID: Maximum(%d) number of retries reached", mid_info->config->boot_retry);
  785. MLGD("STMACH: MID will stay in STATE_OFF.");
  786. mid_info->boot_retry_left = mid_info->config->boot_retry;
  787. mid_info->boot_failed = 1;
  788. return MID_CLEAR_EVENT;
  789. } else if (mid_info->boot_retry_left > 0) {
  790. mid_info->boot_failed = 0;
  791. }
  792. mid_info->boot_retry_left--;
  793. #ifdef PERF_MEASUREMENT
  794. if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemImagesStarted))
  795. MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
  796. if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemImagesFinished))
  797. MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
  798. #endif
  799. if (modem_power_on(mid_info, 0)) {
  800. MLGE("GPIO: MID modem power on failure");
  801. return MID_KEEP_EVENT;
  802. }
  803. if (!mid_gpio_used(mid_info->gpios, GPIO_ID_RESOUT2) || (!mid_gpio_is_ctrl_enabled(mid_info->gpios))) {
  804. /* Flashed variant witout gpio RST2 ctrl - e.g. PC start everything here */
  805. if (my_system(mid_info, mid_info->config->mod_ifup_cmd) != 0) {
  806. /* We always check for a modem dump in shutdown_modem */
  807. /* unlesss we tried retrieveing a dump before we call shutdown */
  808. shutdown_modem(mid_info);
  809. return MID_KEEP_EVENT;
  810. }
  811. if (mid_info->config->enable_at_channel && mid_at_chnl_open(mid_info)) {
  812. MLGE("AT: Unable to open AT channel. MID will shutdown the modem.");
  813. /* We always check for a modem dump in shutdown_modem */
  814. /* unlesss we tried retrieveing a dump before we call shutdown */
  815. shutdown_modem(mid_info);
  816. return MID_KEEP_EVENT;
  817. }
  818. /* And we bypass STATE_BOOT as RESOUT2 will never come */
  819. if (mid_info->config->enable_at_channel)
  820. /* AT channel enabled, we wait for EMRDY */
  821. mid_info->state = STATE_MODINF_UP;
  822. else {
  823. int res = my_system(mid_info, mid_info->config->mod_on_cmd);
  824. if (res != 0) {
  825. /* We always check for a modem dump in shutdown_modem */
  826. /* unlesss we tried retrieveing a dump before we call shutdown */
  827. shutdown_modem(mid_info);
  828. return MID_KEEP_EVENT;
  829. }
  830. /* Go in ON - clear START_EVT and RBT_EVT */
  831. CLEAR_FLAG(mid_info->event, MID_MODEM_START_EVT);
  832. CLEAR_FLAG(mid_info->event, MID_IPC_RBT_EVT);
  833. mid_info->state = STATE_ON;
  834. ipc_prepare_message(&msg, STATECHANGE, "on", get_reason_from_last_event(mid_info));
  835. ipc_send_message(msg);
  836. mid_mfa_notify_on(mid_info->mfa);
  837. }
  838. return MID_KEEP_EVENT;
  839. }
  840. mid_info->state = STATE_BOOT;
  841. ipc_prepare_message(&msg, STATECHANGE, "booting", get_reason_from_last_event(mid_info));
  842. ipc_send_message(msg);
  843. return MID_KEEP_EVENT;
  844. }
  845. static bool mid_statemachine_start_flashing(struct mid* mid_info)
  846. {
  847. MLGD("MID: %s is not empty. MID flash service started(Retries left:%d)", mid_info->config->initial_rdir, mid_info->flash_retry_left);
  848. if (mid_info->flash_retry_left == 0 && !mid_info->flash_failed) {
  849. MLGD("MID: Maximum(%d) number of retries reached, trying to boot modem anyway", mid_info->config->flash_retry);
  850. mid_info->flash_retry_left = mid_info->config->flash_retry;
  851. mid_info->flash_failed = true;
  852. /* The flashing failed n times, lets atleast try to boot modem */
  853. return false;
  854. } else if (mid_info->flash_retry_left > 0) {
  855. mid_info->flash_failed = false;
  856. }
  857. mid_info->flash_retry_left--;
  858. #ifdef PERF_MEASUREMENT
  859. if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemImagesStarted))
  860. MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
  861. #endif
  862. mid_disable_gpio_service_safe_mode(mid_info);
  863. mid_enable_tx_safe_mode(mid_info);
  864. if (unlikely(mid_gpio_assert(mid_info->gpios, GPIO_ID_SERVICE))) {
  865. MLGE("GPIO: Can't assert GPIO_MOD_SERVICE");
  866. mid_enable_gpio_service_safe_mode(mid_info);
  867. return false;
  868. }
  869. if (my_system(mid_info, mid_info->config->mod_prefl_cmd) != 0) {
  870. if (unlikely(mid_gpio_deassert(mid_info->gpios, GPIO_ID_SERVICE)))
  871. MLGE("GPIO: Can't deassert GPIO_MOD_SERVICE");
  872. mid_enable_gpio_service_safe_mode(mid_info);
  873. /* Ignoring return values when cleaning up */
  874. (void)my_system(mid_info, mid_info->config->mod_postfl_cmd);
  875. return false;
  876. }
  877. if (mid_mfa_start(mid_info->mfa)) {
  878. MLGD("MFA started");
  879. } else {
  880. MLGE("MID: No dir cleanup will be performed - flash sequence will be again triggered");
  881. if (unlikely(mid_gpio_deassert(mid_info->gpios, GPIO_ID_SERVICE)))
  882. MLGE("GPIO: Can't deassert GPIO_MOD_SERVICE");
  883. mid_enable_gpio_service_safe_mode(mid_info);
  884. (void)my_system(mid_info, mid_info->config->mod_postfl_cmd);
  885. shutdown_modem(mid_info);
  886. return false;
  887. }
  888. return true;
  889. }
  890. static MID_Event_Oper_t MID_State_Flashing__Event_FLASH_END(struct mid *mid_info)
  891. {
  892. MLGD("MID: Modem flash ended.");
  893. if (!mid_mfa_was_successful(mid_info->mfa)) {
  894. MLGW("STMACH: MFA Flashing failed. Retrying");
  895. if (modem_power_off(mid_info) != 0) {
  896. MLGE("MFA: MID modem power off failure");
  897. }
  898. #ifdef MOTOROLA_FEATURE
  899. if (mot_mid_info.recovery_mode) {
  900. /* Broadcast status if MID was not terminated externally */
  901. if (!(mid_info->event & 1<<MID_SIG_KILL_EVT)) {
  902. union ipc_msg msg;
  903. ipc_prepare_message(&msg, MFARESULT, "fail");
  904. ipc_send_message(msg);
  905. }
  906. /* Exit to recovery executables to potentially retry flashing */
  907. MLGE("Flash fail: Exiting MID in recovery mode.");
  908. exit(EXIT_FAILURE);
  909. }
  910. #endif /* MOTOROLA_FEATURE */
  911. if (!mid_statemachine_start_flashing(mid_info)) {
  912. MLGE("MFA: Failed to start flashing");
  913. }
  914. // If we've given up flashing, we just continue with normal bootup.
  915. if (!mid_info->flash_failed) {
  916. return MID_CLEAR_EVENT;
  917. }
  918. }
  919. if(purgedir(mid_info->config->initial_rdir))
  920. MLGE("MID: Failed to purge dir: %s. Continue anyway", mid_info->config->initial_rdir);
  921. #ifdef MOTOROLA_FEATURE
  922. if (!mot_mid_info.recovery_mode)
  923. {
  924. #endif
  925. /* Since the modem images files is deleted we keep the event */
  926. /* so the modem will be tried to boot(without flashing) in */
  927. /* the next iteration */
  928. if (my_system(mid_info, mid_info->config->mod_postfl_cmd) != 0)
  929. return MID_KEEP_EVENT;
  930. #ifdef MOTOROLA_FEATURE
  931. }
  932. else
  933. {
  934. /* MID was launched in recovery mode: shutdown modem */
  935. my_system(mid_info, mid_info->config->mod_postfl_cmd);
  936. shutdown_modem(mid_info);
  937. /* Broadcast status if MID was not terminated externally */
  938. if (!(mid_info->event & 1<<MID_SIG_KILL_EVT)) {
  939. union ipc_msg msg;
  940. ipc_prepare_message(&msg, MFARESULT, "pass");
  941. ipc_send_message(msg);
  942. }
  943. /* Exit to recovery executables to reboot to normal mode. */
  944. MLGE("Flash success: Exiting MID in recovery mode.");
  945. exit(EXIT_SUCCESS);
  946. }
  947. #endif /* MOTOROLA_FEATURE */
  948. /* Since flashing went well we just continue even if this failed */
  949. /* Modem is turned off by MFA. This may not be correct */
  950. if (unlikely(mid_gpio_deassert(mid_info->gpios, GPIO_ID_SERVICE)))
  951. MLGE("GPIO: Can't deassert GPIO_MOD_SERVICE");
  952. if (unlikely(mid_gpio_deassert(mid_info->gpios, GPIO_ID_PWRRSTOUT)))
  953. MLGE("GPIO: Can't deassert GPIO_PWRRSTOUT");
  954. /* Set all interface in safe mode */
  955. mid_enable_gpio_service_safe_mode(mid_info);
  956. mid_enable_io_safe_mode(mid_info);
  957. /* Sanity sleep to let time for HW */
  958. MLGD("STMACH: MID will be idle for 50 millisecond to allow safe mode propagation on IOs.");
  959. usleep(50000);
  960. /* Check if modem is down - otherwise power it off */
  961. if (mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2) || mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN)
  962. || mid_info->config->flash_force_pwroff) {
  963. if (mid_info->config->flash_force_pwroff)
  964. /* For modem that does not automaticaly power off, we can force it */
  965. MLGD("STMACH: Option flash_force_pwroff is set. Modem power_off function is called now.");
  966. else
  967. MLGD("STMACH: Modem is ON according RESOUT2 and / or PWRRSTIN level. Modem power_off function is called now.");
  968. shutdown_modem(mid_info);
  969. }
  970. return mid_statemachine_try_boot(mid_info);
  971. }
  972. /***************
  973. OFF
  974. ***************/
  975. MID_Event_Oper_t MID_State_Off__Event_SIG_KILL(struct mid *mid_info)
  976. {
  977. MLGD("STMACH: MID execute Action: SIG_KILL_EVT processing.");
  978. state_all_evt_sig_kill(mid_info);
  979. return MID_KEEP_EVENT;
  980. }
  981. /* Only used in the function below. We cannot use stack variable when creating thread. */
  982. /* The stack is changed before the thread use the variable */
  983. static int _timeout;
  984. MID_Event_Oper_t MID_State_Off__Event_MODEM_START__IPC_RBT(struct mid *mid_info)
  985. {
  986. int res;
  987. apr_status_t status;
  988. MLGD("STMACH: MID execute Action: START / IPC_RBT_EVT processing.");
  989. if (FLAG_UP(mid_info->event, MID_MODEM_HALT_EVT)) {
  990. CLEAR_FLAG(mid_info->event, MID_MODEM_HALT_EVT);
  991. MLGD("STMACH: MID_MODEM_HALT_EVT event cleared.");
  992. return MID_CLEAR_EVENT;
  993. }
  994. mid_info->kill_threads = 0;
  995. /* Since the current setup doesn't always support RSTIN we need to keep modem on state */
  996. if (!mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN))
  997. mid_info->modem_is_on = 0;
  998. #ifdef PERF_MEASUREMENT
  999. if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemBootStarted))
  1000. MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
  1001. #endif
  1002. /* TODO: Consider remove this when crashdump is tested and working */
  1003. if (mid_info->config->crashdump_dev_mode == -1) {
  1004. res = start_delayed_dump(&mid_info->mid_crashdump_td, mid_info, _timeout);
  1005. if (res) {
  1006. MLGE("MID: MID delayed crashdump thread creation failure: %s", strerror(res));
  1007. }
  1008. mid_info->flash_retry_left = mid_info->config->flash_retry;
  1009. mid_info->boot_retry_left = mid_info->config->boot_retry;
  1010. mid_info->boot_failed = 0;
  1011. mid_info->flash_failed = 0;
  1012. mid_info->state = STATE_ON;
  1013. return MID_CLEAR_EVENT;
  1014. }
  1015. /* Need to handle runtime mode SERVICE specificaly */
  1016. if (strncmp("service",mid_info->config->runtime_mode,strlen("service")) == 0) {
  1017. mid_disable_gpio_service_safe_mode(mid_info);
  1018. if (unlikely(mid_gpio_assert(mid_info->gpios, GPIO_ID_SERVICE))) {
  1019. MLGE("GPIO: Can't assert GPIO_MOD_SERVICE");
  1020. mid_enable_gpio_service_safe_mode(mid_info);
  1021. return MID_CLEAR_EVENT;
  1022. }
  1023. if (my_system(mid_info, mid_info->config->mod_prefl_cmd) != 0) {
  1024. /* Ignoring return values when cleaning up */
  1025. (void)mid_gpio_deassert(mid_info->gpios, GPIO_ID_SERVICE);
  1026. mid_enable_gpio_service_safe_mode(mid_info);
  1027. (void)my_system(mid_info, mid_info->config->mod_postfl_cmd);
  1028. return MID_CLEAR_EVENT;
  1029. }
  1030. #if defined(MOTOROLA_FEATURE)
  1031. (void)my_system(mid_info, mot_mid_info.svc_mode_cmd);
  1032. #endif
  1033. if (modem_power_on(mid_info, 0) != 0) {
  1034. MLGE("GPIO: Unable to power on modem!");
  1035. /* Ignoring return values when cleaning up */
  1036. (void)mid_gpio_deassert(mid_info->gpios, GPIO_ID_SERVICE);
  1037. mid_enable_gpio_service_safe_mode(mid_info);
  1038. (void)my_system(mid_info, mid_info->config->mod_postfl_cmd);
  1039. return MID_CLEAR_EVENT;
  1040. }
  1041. MLGD("MID: Entered service mode, update mid.conf and restart host "
  1042. "in order to exit service mode");
  1043. return MID_CLEAR_EVENT;
  1044. }
  1045. /* FLASH OPERATION TRIGGER */
  1046. MLGD("isdirempty(\"%s\")==%d", mid_info->config->initial_rdir, isdirempty(mid_info->config->initial_rdir));
  1047. MLGD("initial_enable_bootldr==%d", mid_info->config->initial_enable_bootldr);
  1048. MLGD("flash_failed=%d", mid_info->flash_failed);
  1049. if (!isdirempty(mid_info->config->initial_rdir) && (!mid_info->config->initial_enable_bootldr) && !mid_info->flash_failed) {
  1050. union ipc_msg msg;
  1051. if (!mid_statemachine_start_flashing(mid_info))
  1052. return MID_KEEP_EVENT;
  1053. MLGD("Entering FLASHING state");
  1054. mid_info->state = STATE_FLASHING;
  1055. ipc_prepare_message(&msg, STATECHANGE, "flashing", get_reason_from_last_event(mid_info));
  1056. ipc_send_message(msg);
  1057. return MID_CLEAR_EVENT;
  1058. }
  1059. if (mid_info->config->initial_enable_bootldr) {
  1060. /* FLASHLESS VARIANT - FIRMWARE UPLOAD */
  1061. MLGD("MID: MID bootloader started(Retries left:%d)",mid_info->boot_retry_left);
  1062. if (mid_info->boot_retry_left == 0 && !mid_info->boot_failed) {
  1063. mid_info->boot_retry_left = mid_info->config->boot_retry;
  1064. mid_info->boot_failed = 1;
  1065. if (mid_info->config->reboot_on_failure) {
  1066. #if defined(MOTOROLA_FEATURE)
  1067. mid_statemachine_log_panic_apr("Subtype: MID bootloader: maximum number of retries reached.\n", mid_info->config->critical_panic_detection_file);
  1068. #endif
  1069. mid_platform_reboot(mid_info);
  1070. }
  1071. MLGD("MID: Maximum(%d) number of retries reached", mid_info->config->boot_retry);
  1072. MLGD("STMACH: MID will stay in STATE_OFF.");
  1073. return MID_CLEAR_EVENT;
  1074. } else if (mid_info->boot_retry_left > 0) {
  1075. mid_info->boot_failed = 0;
  1076. }
  1077. mid_info->boot_retry_left--;
  1078. if (my_system(mid_info, mid_info->config->mod_prefl_cmd) != 0)
  1079. return MID_KEEP_EVENT;
  1080. mid_info->long_ops_result = MID_FLBOOT_OK;
  1081. #ifdef PERF_MEASUREMENT
  1082. if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemImagesStarted))
  1083. MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
  1084. #endif
  1085. if (mid_configure_dev(mid_info->config->prim_dev_config, mid_info->config->prim_dev_config->devtype) != 0) {
  1086. MLGE("MID: Error on primary device configuration");
  1087. return MID_KEEP_EVENT;
  1088. }
  1089. if (mid_info->config->link_switch && (mid_configure_dev(mid_info->config->sec_dev_config,
  1090. mid_info->config->sec_dev_config->devtype) != 0)) {
  1091. MLGE("MID: Error on secondary device configuration");
  1092. return MID_KEEP_EVENT;
  1093. }
  1094. if ((status = apr_thread_create(&mid_info->mid_flboot_td, NULL, mid_info->moli_boot, mid_info, mid_info->pool)) != APR_SUCCESS) {
  1095. char message[100];
  1096. MLGE("MID: MID moli_boot thread creation failure: %s",
  1097. apr_strerror(status, message, sizeof(message)));
  1098. (void)my_system(mid_info, mid_info->config->mod_postfl_cmd);
  1099. shutdown_modem(mid_info);
  1100. return MID_KEEP_EVENT;
  1101. }
  1102. mid_info->state = STATE_BOOT;
  1103. return MID_KEEP_EVENT;
  1104. }
  1105. return mid_statemachine_try_boot(mid_info);
  1106. }
  1107. /***************
  1108. BOOT
  1109. ***************/
  1110. MID_Event_Oper_t MID_State_Boot__Event_LONG_OPS(struct mid *mid_info)
  1111. {
  1112. int res;
  1113. union ipc_msg msg;
  1114. MLGD("STMACH: MID execute Action: LONG_OPS_EVT processing. Firmware upload is completed.");
  1115. #ifdef PERF_MEASUREMENT
  1116. if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemImagesFinished))
  1117. MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
  1118. #endif
  1119. if (mid_info->long_ops_result != MID_FLBOOT_OK) {
  1120. MLGE("MID: MID Failure on firmware upload. Try to boot again");
  1121. (void)my_system(mid_info, mid_info->config->mod_postfl_cmd);
  1122. shutdown_modem(mid_info);
  1123. return MID_CLEAR_EVENT;
  1124. }
  1125. /* Flashless variant without gpio RST2 ctrl assume modem is ready and start RFM */
  1126. /* With RST2 support we just stay in current state and wait for the RST2 event */
  1127. MLGD("MID: MID Firmware upload completed");
  1128. if (!mid_gpio_used(mid_info->gpios, GPIO_ID_RESOUT2)) {
  1129. if (!mid_info->config->use_on_sw_c) {
  1130. /* OnSwA - deassert power ON */
  1131. if (mid_gpio_deassert(mid_info->gpios, GPIO_ID_ON))
  1132. MLGE("GPIO: Can't deassert GPIO_ON");
  1133. }
  1134. res = my_system(mid_info, mid_info->config->mod_postfl_cmd);
  1135. if (res != 0)
  1136. return MID_CLEAR_EVENT;
  1137. res = my_system(mid_info, mid_info->config->mod_ifup_cmd);
  1138. if (res != 0) {
  1139. shutdown_modem(mid_info);
  1140. return MID_CLEAR_EVENT;
  1141. }
  1142. /* RFM will be started when receiving the booting ipc event */
  1143. ipc_prepare_message(&msg, STATECHANGE, "booting", get_reason_from_last_event(mid_info));
  1144. ipc_send_message(msg);
  1145. if (mid_info->config->rfm_delay) {
  1146. apr_status_t status;
  1147. status = apr_thread_create(&mid_info->mid_rfmsleep_td, NULL, &rfm_sleep, mid_info, mid_info->pool);
  1148. if (status != APR_SUCCESS) {
  1149. char message[100];
  1150. MLGE("MID: MID rfm_sleep thread creation failure: %s",
  1151. apr_strerror(status, message, sizeof(message)));
  1152. shutdown_modem(mid_info);
  1153. return MID_CLEAR_EVENT;
  1154. }
  1155. mid_info->state = STATE_MODINF_UP;
  1156. return MID_CLEAR_EVENT;
  1157. }
  1158. if (mid_info->config->enable_at_channel) {
  1159. if (mid_at_chnl_open(mid_info)) {
  1160. MLGE("AT: Unable to open AT channel. MID will shutdown the modem.");
  1161. shutdown_modem(mid_info);
  1162. return MID_CLEAR_EVENT;
  1163. }
  1164. mid_info->state = STATE_MODINF_UP;
  1165. return MID_CLEAR_EVENT;
  1166. }
  1167. /* We just set the MID_CFRDY_EVT event and enter the MODINF_UP state so */
  1168. /* so we can handle the code at the same place */
  1169. SET_FLAG(mid_info->event, MID_CFRDY_EVT);
  1170. MLGD("STMACH: MID_CFRDY_EVT event set.");
  1171. mid_info->state = STATE_MODINF_UP;
  1172. return MID_CLEAR_EVENT;
  1173. }
  1174. return MID_CLEAR_EVENT;
  1175. }
  1176. MID_Event_Oper_t MID_State_Boot__Event_GPIO_RST2(struct mid *mid_info)
  1177. {
  1178. int res;
  1179. union ipc_msg msg;
  1180. MLGD("STMACH: MID execute Action: GPIO_RST2_EVT processing.");
  1181. if (mid_info->power_on_release) {
  1182. /* OnSwA specific */
  1183. MLGD("GPIO: De-assert MOD ON pin");
  1184. res = mid_gpio_deassert(mid_info->gpios, GPIO_ID_ON);
  1185. if (unlikely(res)) {
  1186. MLGE("GPIO: Can't deassert GPIO_ON");
  1187. mid_info->power_on_release = 0;
  1188. }
  1189. mid_info->power_on_release = 0;
  1190. }
  1191. #ifdef PERF_MEASUREMENT
  1192. if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemRST2))
  1193. MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
  1194. #endif
  1195. if (!mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2)) {
  1196. return MID_CLEAR_EVENT;
  1197. }
  1198. /* We only do this for flashless, for the flashed variant we don't execute prefl_ and postfl_cmd */
  1199. if (mid_info->config->initial_enable_bootldr) {
  1200. res = my_system(mid_info, mid_info->config->mod_postfl_cmd);
  1201. if (res != 0) {
  1202. goto error_exit_shutdown;
  1203. }
  1204. }
  1205. res = my_system(mid_info, mid_info->config->mod_ifup_cmd);
  1206. if (res != 0) {
  1207. goto error_exit_shutdown;
  1208. }
  1209. /* RFM will be started when receiving the booting ipc event */
  1210. ipc_prepare_message(&msg, STATECHANGE, "booting", get_reason_from_last_event(mid_info));
  1211. ipc_send_message(msg);
  1212. if (mid_info->config->rfm_delay) {
  1213. apr_status_t status;
  1214. status = apr_thread_create(&mid_info->mid_rfmsleep_td, NULL, &rfm_sleep, mid_info, mid_info->pool);
  1215. if (status != APR_SUCCESS) {
  1216. char message[100];
  1217. MLGE("MID: MID rfm_sleep thread creation failure: %s",
  1218. apr_strerror(status, message, sizeof(message)));
  1219. goto error_exit_shutdown;
  1220. }
  1221. mid_info->state = STATE_MODINF_UP;
  1222. goto clean_exit;
  1223. }
  1224. if (mid_info->config->enable_at_channel) {
  1225. if (mid_at_chnl_open(mid_info)) {
  1226. MLGE("AT: Unable to open AT channel. MID will shutdown the modem.");
  1227. goto error_exit_shutdown;
  1228. }
  1229. mid_info->state = STATE_MODINF_UP;
  1230. goto clean_exit;
  1231. }
  1232. /* We just set the MID_CFRDY_EVT event and enter the MODINF_UP state so */
  1233. /* so we can handle the code at the same place */
  1234. SET_FLAG(mid_info->event, MID_CFRDY_EVT);
  1235. MLGD("STMACH: MID_CFRDY_EVT event set.");
  1236. mid_info->state = STATE_MODINF_UP;
  1237. clean_exit:
  1238. if (mid_info->fw_upgr_flash_reply_msg) {
  1239. if (ipc_send_async_reply(&mid_info->fw_upgr_flash_reply_msg, "OK"))
  1240. MLGE("DBUS: Failed to send fw upgrade reply");
  1241. }
  1242. return MID_CLEAR_EVENT;
  1243. error_exit

Large files files are truncated, but you can click here to view the full file