[9610] chub: update chub reset sequence
authorBoojin Kim <boojin.kim@samsung.com>
Mon, 22 Oct 2018 09:42:55 +0000 (18:42 +0900)
committerDongsik Son <dongsik.son@samsung.com>
Wed, 24 Oct 2018 12:52:40 +0000 (21:52 +0900)
Itmon error occured during chub reset because AP access CHUB-GRP before tzpc setting.
Orignal sequence is below.
1.PMUCAL:assert ->  2.PMUCAL:release_config -> 3.FW download -> 4. tzpc(for baaw) + PMUCAL:release(reset)
New sequence moves the tzpc setting from 2th to 4th as following.
1.PMUCAL:assert ->  2.PMUCAL:release_config + tzpc(for baaw) -> 3.FW download -> 4. PMUCAL:release(reset)

Change-Id: I6b4c306d9692874e5a72d85ea500861eab63e296
Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
drivers/staging/nanohub/chub.c
drivers/staging/nanohub/chub.h
drivers/staging/nanohub/chub_dbg.c
drivers/staging/nanohub/chub_log.c

index be9edf4d69ccd1accd65b11011358e8f2ef958e5..eb174d8605306bf88539dd6b53fd7a3391940628 100644 (file)
 enum { CHUB_ON, CHUB_OFF };
 enum { C2A_ON, C2A_OFF };
 
-int contexthub_get_token(struct contexthub_ipc_info *ipc, enum access_type acc)
+static DEFINE_MUTEX(reset_mutex);
+static DEFINE_MUTEX(pmu_shutdown_mutex);
+static inline int contexthub_get_token(struct contexthub_ipc_info *ipc, enum access_type acc)
 {
-       if (acc == HW_ACCESS)
-               return !atomic_read(&ipc->in_pmu_shutdown);
-
-       if (acc == IPC_ACCESS)
+       if (acc == HW_ACCESS) {
+               mutex_lock(&pmu_shutdown_mutex);
+               dev_info(ipc->dev, "%s: enter shutdown\n", __func__);
+       } else if (acc == IPC_ACCESS)
                return (atomic_read(&ipc->chub_status) == CHUB_ST_RUN) && !atomic_read(&ipc->in_reset);
+       return true;
+}
 
-       return -EINVAL;
+static inline void contexthub_put_token(struct contexthub_ipc_info *ipc, enum access_type acc)
+{
+       if (acc == HW_ACCESS) {
+               dev_info(ipc->dev, "%s: out shutdown\n", __func__);
+               mutex_unlock(&pmu_shutdown_mutex);
+       }
 }
 
 /* host interface functions */
@@ -77,12 +86,13 @@ int contexthub_is_run(struct contexthub_ipc_info *ipc)
 int contexthub_request(struct contexthub_ipc_info *ipc, enum access_type acc)
 {
        if (!contexthub_get_token(ipc, acc)) {
-               dev_info(ipc->dev, "%s: %s isn't accesable\n",
-                       __func__, (acc == HW_ACCESS) ? "hw" : "ipc");
+               dev_info(ipc->dev, "%s: %s isn't accesable: chub_status: %d, in_reset:%d\n",
+                       __func__, (acc == HW_ACCESS) ? "hw" : "ipc",
+                       atomic_read(&ipc->chub_status), atomic_read(&ipc->in_reset));
                return -EINVAL;
        }
 
-       if (!ipc->powermode)
+       if ((acc == HW_ACCESS) || !ipc->powermode)
                return 0;
 
 #ifdef CONFIG_CHRE_SENSORHUB_HAL
@@ -93,9 +103,11 @@ int contexthub_request(struct contexthub_ipc_info *ipc, enum access_type acc)
 }
 
 /* rlease contexthub to host driver */
-void contexthub_release(struct contexthub_ipc_info *ipc)
+void contexthub_release(struct contexthub_ipc_info *ipc, enum access_type acc)
 {
-       if (!ipc->powermode)
+       contexthub_put_token(ipc, acc);
+
+       if ((acc == HW_ACCESS) || !ipc->powermode)
                return;
 
 #ifdef CONFIG_CHRE_SENSORHUB_HAL
@@ -289,7 +301,6 @@ static void handle_debug_work(struct contexthub_ipc_info *ipc, enum chub_err_typ
 {
        int need_reset;
        int alive = contexthub_lowlevel_alive(ipc);
-       int ret;
 
        /* handle fw dbg */
        if (err == CHUB_ERR_NANOHUB) {
@@ -324,19 +335,26 @@ static void handle_debug_work(struct contexthub_ipc_info *ipc, enum chub_err_typ
 
        /* reset */
        if (need_reset) {
-#ifdef CHUB_RESET_ENABLE
+#if defined(CHUB_RESET_ENABLE)
+               int ret;
+
+               dev_info(ipc->dev, "%s: request silent reset. err:%d, alive:%d, status:%d, in-reset:%d\n",
+                       __func__, err, alive, __raw_readl(&ipc->chub_status),
+                       __raw_readl(&ipc->in_reset));
+
                ret = contexthub_reset(ipc, 0);
                if (ret)
                        dev_warn(ipc->dev, "%s: fails to reset:%d. status:%d\n",
                                __func__, ret, __raw_readl(&ipc->chub_status));
-               else {
+               else
                        /* TODO: recovery */
                        dev_info(ipc->dev, "%s: chub reset! should be recovery\n",
                                __func__);
-                       if (err == CHUB_ERR_FW_WDT && ipc->irq_wdt)
-                               enable_irq(ipc->irq_wdt);
-               }
 #else
+               dev_info(ipc->dev, "%s: chub hang. wait for sensor driver reset\n",
+                       __func__, err, alive, __raw_readl(&ipc->chub_status),
+                       __raw_readl(&ipc->in_reset));
+
                atomic_set(&ipc->chub_status, CHUB_ST_HANG);
 #endif
        }
@@ -440,10 +458,13 @@ int contexthub_ipc_read(struct contexthub_ipc_info *ipc, uint8_t *rx, int max_le
        rxbuf = ipc_read_data(IPC_DATA_C2A, &size);
 #endif
 
-       if (size > 0)
+       if (size > 0) {
+               contexthub_put_token(ipc, IPC_ACCESS);
                return contexthub_read_process(rx, rxbuf, size);
+       }
 
 fail_get_channel:
+       contexthub_put_token(ipc, IPC_ACCESS);
        request_debug_work(ipc, CHUB_ERR_READ_FAIL, 0);
        return -EINVAL;
 }
@@ -465,6 +486,7 @@ int contexthub_ipc_write(struct contexthub_ipc_info *ipc,
                request_debug_work(ipc, CHUB_ERR_WRITE_FAIL, 0);
                length = 0;
        }
+       contexthub_put_token(ipc, IPC_ACCESS);
        return length;
 }
 
@@ -506,8 +528,11 @@ static int contexthub_hw_reset(struct contexthub_ipc_info *ipc,
        atomic_set(&ipc->read_lock.cnt, 0x0);
 
        /* chub err init */
-       for (i = 0; i < CHUB_ERR_MAX; i++)
+       for (i = 0; i < CHUB_ERR_MAX; i++) {
+               if (i == CHUB_ERR_RESET_CNT)
+                       continue;
                ipc->err_cnt[i] = 0;
+       }
 
        ipc->read_lock.flag = 0;
        ipc_hw_write_shared_reg(AP, ipc->os_load, SR_BOOT_MODE);
@@ -643,20 +668,6 @@ int contexthub_ipc_write_event(struct contexthub_ipc_info *ipc,
                break;
        case MAILBOX_EVT_RESET:
                if (atomic_read(&ipc->chub_status) == CHUB_ST_SHUTDOWN) {
-                       if (ipc->block_reset) {
-                               /* tzpc setting */
-                               ret = exynos_smc(SMC_CMD_CONN_IF,
-                                       (EXYNOS_SHUB << 32) |
-                                       EXYNOS_SET_CONN_TZPC, 0, 0);
-                               if (ret) {
-                                       pr_err("%s: TZPC setting fail\n",
-                                               __func__);
-                                       return -EINVAL;
-                               }
-
-                               /* baaw config */
-                               contexthub_config_init(ipc);
-                       }
                        ret = contexthub_hw_reset(ipc, event);
                } else {
                        dev_err(ipc->dev,
@@ -680,6 +691,19 @@ int contexthub_ipc_write_event(struct contexthub_ipc_info *ipc,
                                pr_err("%s: reset release cfg fail\n", __func__);
                                return ret;
                        }
+
+                       /* tzpc setting */
+                       ret = exynos_smc(SMC_CMD_CONN_IF,
+                               (EXYNOS_SHUB << 32) |
+                               EXYNOS_SET_CONN_TZPC, 0, 0);
+                       if (ret) {
+                               pr_err("%s: TZPC setting fail\n",
+                                       __func__);
+                               return -EINVAL;
+                       }
+                       dev_info(ipc->dev, "%s: tzpc setted\n", __func__);
+                               /* baaw config */
+                       contexthub_config_init(ipc);
                } else {
                        val = __raw_readl(ipc->pmu_chub_reset +
                                          REG_CHUB_CPU_STATUS);
@@ -771,6 +795,7 @@ int contexthub_ipc_write_event(struct contexthub_ipc_info *ipc,
                break;
        }
 
+       contexthub_put_token(ipc, IPC_ACCESS);
        return ret;
 }
 
@@ -851,31 +876,38 @@ out:
        return ret;
 }
 
-static DEFINE_MUTEX(reset_mutex);
 int contexthub_reset(struct contexthub_ipc_info *ipc, bool force_load)
 {
        int ret;
 
+       dev_info(ipc->dev, "%s: force:%d, status:%d, in-reset:%d\n",
+               __func__, force_load, atomic_read(&ipc->chub_status), atomic_read(&ipc->in_reset));
        mutex_lock(&reset_mutex);
-       dev_info(ipc->dev, "%s: status:%d\n", __func__, atomic_read(&ipc->chub_status));
        if (!force_load && (atomic_read(&ipc->chub_status) == CHUB_ST_RUN)) {
                mutex_unlock(&reset_mutex);
+               dev_info(ipc->dev, "%s: out status:%d\n", __func__, atomic_read(&ipc->chub_status));
                return 0;
        }
        atomic_inc(&ipc->in_reset);
+#ifndef CONFIG_CHRE_SENSORHUB_HAL /* retry exam */
+retry:
+#endif
+       dev_info(ipc->dev, "%s: start reset status:%d\n", __func__, atomic_read(&ipc->chub_status));
        if (!ipc->block_reset) {
                /* core reset */
                ipc_add_evt(IPC_EVT_A2C, IRQ_EVT_A2C_SHUTDOWN);
                msleep(100);    /* wait for shut down time */
        }
 
-       atomic_inc(&ipc->in_pmu_shutdown);
+       mutex_lock(&pmu_shutdown_mutex);
+       dev_info(ipc->dev, "%s: enter shutdown\n", __func__);
        ret = contexthub_ipc_write_event(ipc, MAILBOX_EVT_SHUTDOWN);
        if (ret) {
                dev_err(ipc->dev, "%s: shutdonw fails, ret:%d\n", __func__, ret);
                goto out;
        }
-       atomic_dec(&ipc->in_pmu_shutdown);
+       dev_info(ipc->dev, "%s: out shutdown\n", __func__);
+       mutex_unlock(&pmu_shutdown_mutex);
 
        if (ipc->block_reset || force_load) {
                ret = contexthub_download_image(ipc, IPC_REG_BL);
@@ -898,16 +930,41 @@ int contexthub_reset(struct contexthub_ipc_info *ipc, bool force_load)
        ret = contexthub_ipc_write_event(ipc, MAILBOX_EVT_RESET);
        if (ret)
                dev_err(ipc->dev, "%s: reset fails, ret:%d\n", __func__, ret);
-       else
+       else {
                dev_info(ipc->dev, "%s: chub reseted! (cnt:%d)\n",
                        __func__, ipc->err_cnt[CHUB_ERR_RESET_CNT]);
-
-       if (!ret)
                ipc->err_cnt[CHUB_ERR_RESET_CNT]++;
+               atomic_dec(&ipc->in_reset);
+#ifndef CONFIG_CHRE_SENSORHUB_HAL
+               ret = request_wakeup(ipc->data);
+               if (ret)
+                       dev_err(ipc->dev, "%s: fails to wakeup after reset, ret:%d\n", __func__, ret);
+               else
+                       release_wakeup(ipc->data);
+               if (ipc->irq_wdt && ipc->irq_wdt_disabled) {
+                       enable_irq(ipc->irq_wdt);
+                       ipc->irq_wdt_disabled = 0;
+               }
+#endif
+       }
 
 out:
-       atomic_dec(&ipc->in_reset);
+       if (!ret) {
+               dev_info(ipc->dev, "%s: chub reseted and work (cnt:%d)\n",
+                       __func__, ipc->err_cnt[CHUB_ERR_RESET_CNT]);
+               ipc->err_cnt[CHUB_ERR_RESET_CNT] = 0;
+       } else {
+#ifndef CONFIG_CHRE_SENSORHUB_HAL
+               atomic_inc(&ipc->in_reset);
+               if (ipc->err_cnt[CHUB_ERR_RESET_CNT] > CHUB_RESET_THOLD)
+                       msleep(WAIT_TIMEOUT_MS * CHUB_RESET_THOLD);
+               else
+                       msleep(WAIT_TIMEOUT_MS);
+               goto retry;
+#endif
+       }
        mutex_unlock(&reset_mutex);
+
        return ret;
 }
 
@@ -1032,6 +1089,7 @@ static irqreturn_t contexthub_irq_wdt_handler(int irq, void *data)
 
        dev_info(ipc->dev, "%s calledn", __func__);
        disable_irq_nosync(ipc->irq_wdt);
+       ipc->irq_wdt_disabled = 1;
        request_debug_work(ipc, CHUB_ERR_FW_WDT, 1);
 
        return IRQ_HANDLED;
@@ -1137,6 +1195,7 @@ static __init int contexthub_ipc_hw_init(struct platform_device *pdev,
                                chub->irq_wdt, ret);
                        return ret;
                }
+               chub->irq_wdt_disabled = 0;
        } else {
                dev_info(dev, "don't use wdt irq:%d\n", irq);
        }
@@ -1352,7 +1411,6 @@ static int contexthub_ipc_probe(struct platform_device *pdev)
 
        atomic_set(&chub->chub_status, CHUB_ST_NO_POWER);
        atomic_set(&chub->in_reset, 0);
-       atomic_set(&chub->in_pmu_shutdown, 0);
        chub->powermode = 0; /* updated by fw bl */
        chub->cur_err = 0;
        for (i = 0; i < CHUB_ERR_MAX; i++)
index c49c32621d903f9c34f0b74c02f88ff4b1fe3417..5c3ee1a3caf14b7b904c127a27db503c92273b94 100644 (file)
@@ -72,7 +72,6 @@
 })
 
 #define CHUB_RESET_ENABLE
-
 enum mailbox_event {
        MAILBOX_EVT_UTC_MAX = IPC_DEBUG_UTC_MAX,
        MAILBOX_EVT_DUMP_STATUS = IPC_DEBUG_DUMP_STATUS,
@@ -176,11 +175,11 @@ struct contexthub_ipc_info {
        unsigned long clkrate;
        atomic_t chub_status;
        atomic_t in_reset;
-       atomic_t in_pmu_shutdown;
        atomic_t irq1_apInt;
        atomic_t wakeup_chub;
        int irq_mailbox;
        int irq_wdt;
+       bool irq_wdt_disabled;
        int err_cnt[CHUB_ERR_MAX];
        u32 cur_err;
        int utc_run;
@@ -287,7 +286,6 @@ struct contexthub_ipc_info {
 
 enum access_type { HW_ACCESS, IPC_ACCESS };
 
-int contexthub_get_token(struct contexthub_ipc_info *ipc, enum access_type acc);
 int contexthub_ipc_write_event(struct contexthub_ipc_info *data,
                                enum mailbox_event event);
 int contexthub_ipc_read(struct contexthub_ipc_info *ipc,
@@ -301,5 +299,5 @@ int contexthub_wakeup(struct contexthub_ipc_info *data, int evt);
 
 int contexthub_is_run(struct contexthub_ipc_info *ipc);
 int contexthub_request(struct contexthub_ipc_info *ipc, enum access_type acc);
-void contexthub_release(struct contexthub_ipc_info *ipc);
+void contexthub_release(struct contexthub_ipc_info *ipc, enum access_type acc);
 #endif
index 61f7be9e3b39379498703e973997bd3c9db572ea..f3c5a008b1fac6c723b3180158f5a75dea552b95 100644 (file)
@@ -69,9 +69,9 @@ void chub_dbg_dump_gpr(struct contexthub_ipc_info *ipc)
                    readl(ipc->chub_dumpgrp + REG_CHUB_DUMPGPR_PCR);
 
                for (i = 0; i <= GPR_PC_INDEX; i++)
-                       pr_info("gpr: R%d: 0x%x\n", i, p_dump->gpr[i]);
+                       pr_info("R%d: 0x%x\n", i, p_dump->gpr[i]);
 
-               contexthub_release(ipc);
+               contexthub_release(ipc, HW_ACCESS);
        }
 }
 
@@ -131,7 +131,7 @@ void chub_dbg_dump_ram(struct contexthub_ipc_info *ipc, enum chub_err_type reaso
                              ipc_get_base(IPC_REG_DUMP),
                              ipc_get_chub_mem_size());
 
-               contexthub_release(ipc);
+               contexthub_release(ipc, HW_ACCESS);
        }
 }
 
@@ -172,7 +172,7 @@ static void chub_dbg_dump_status(struct contexthub_ipc_info *ipc)
        /* dump nanohub kernel status */
        contexthub_ipc_write_event(ipc, MAILBOX_EVT_DUMP_STATUS);
        log_flush(ipc->fw_log);
-       contexthub_release(ipc);
+       contexthub_release(ipc, IPC_ACCESS);
 }
 
 void chub_dbg_dump_hw(struct contexthub_ipc_info *ipc, enum chub_err_type reason)
@@ -252,12 +252,13 @@ static ssize_t chub_bin_sram_read(struct file *file, struct kobject *kobj,
 
        dev_dbg(dev, "%s(%lld, %zu)\n", __func__, off, size);
 
-       if (!contexthub_get_token(dev_get_drvdata(dev), HW_ACCESS)) {
+       if (contexthub_request(dev_get_drvdata(dev), HW_ACCESS)) {
                pr_warn("%s: chub isn't run\n", __func__);
                return -EINVAL;
        }
 
        memcpy_fromio(buf, battr->private + off, size);
+       contexthub_release(dev_get_drvdata(dev), HW_ACCESS);
        return size;
 }
 
@@ -345,12 +346,13 @@ static ssize_t chub_utc_store(struct device *dev,
        dev_info(ipc->dev, "%s: event:%d\n", __func__, event);
 
        if (!err) {
-               err = contexthub_request(ipc, IPC_ACCESS);
-               if (err)
-                       pr_err("%s: fails to request contexthub. ret:%d\n", __func__, err);
+               if (contexthub_request(ipc, IPC_ACCESS)) {
+                       pr_err("%s: fails to request contexthub\n", __func__);
+                       return 0;
+               }
 
                contexthub_ipc_write_event(ipc, event);
-               contexthub_release(ipc);
+               contexthub_release(ipc, IPC_ACCESS);
                return count;
        } else {
                return 0;
@@ -378,10 +380,9 @@ static ssize_t chub_ipc_store(struct device *dev,
                return -EINVAL;
        }
 
-       ret = contexthub_request(ipc, IPC_ACCESS);
-       if (ret) {
-               dev_err(ipc->dev, "%s: fails to request contexthub. ret:%d\n", __func__, ret);
-               return ret;
+       if (contexthub_request(ipc, IPC_ACCESS)) {
+               dev_err(ipc->dev, "%s: fails to request contexthub. ret:%d\n", __func__);
+               return -EINVAL;
        }
 
        ret = contexthub_ipc_write_event(ipc, (u32)IPC_DEBUG_UTC_IPC_TEST_START);
@@ -420,7 +421,7 @@ out:
                count = ret;
        }
 
-       contexthub_release(ipc);
+       contexthub_release(ipc, IPC_ACCESS);
        return count;
 }
 
@@ -488,7 +489,7 @@ static ssize_t chub_wakeup_store(struct device *dev,
        if (event)
                ret = contexthub_request(ipc, IPC_ACCESS);
        else
-               contexthub_release(ipc);
+               contexthub_release(ipc, IPC_ACCESS);
 
        return ret ? ret : count;
 }
index 123c5cd5486ba3337e8f595cda7dc0c78ca4a3f8..d34a37c6137b118e789624cc66d05a46349c1172 100644 (file)
@@ -159,11 +159,16 @@ static void log_flush_all(void)
        struct log_buffer_info *info;
 
        list_for_each_entry(info, &log_list_head, list) {
-               if (info && !contexthub_get_token(dev_get_drvdata(info->dev), HW_ACCESS)) {
+               if (!info) {
+                       pr_warn("%s: fails get info\n", __func__);
+                       return;
+               }
+               if (contexthub_request(dev_get_drvdata(info->dev), IPC_ACCESS)) {
                        pr_warn("%s: chub isn't run\n", __func__);
                        return;
                }
            log_flush(info);
+               contexthub_release(dev_get_drvdata(info->dev), IPC_ACCESS);
        }
 }
 
@@ -460,10 +465,10 @@ static ssize_t chub_log_flush_save(struct device *dev,
        err = kstrtol(&buf[0], 10, &event);
        if (!err) {
                if (!auto_log_flush_ms) {
-                       err = contexthub_request(ipc, HW_ACCESS);
+                       err = contexthub_request(ipc, IPC_ACCESS);
                        if (!err) {
                                log_flush_all();
-                               contexthub_release(ipc);
+                               contexthub_release(ipc, IPC_ACCESS);
                        } else {
                                pr_err("%s: fails to flush log\n", __func__);
                        }