From: Boojin Kim Date: Thu, 20 Dec 2018 04:14:38 +0000 (+0900) Subject: [ERD][APR-103] [COMMON]chub: support runtimelog X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=e39fcd4eff05a291068beffd118f4164d6f80d05;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git [ERD][APR-103] [COMMON]chub: support runtimelog Change-Id: I4f67cdc83e86f9994e233dceb517ae00161343f0 Signed-off-by: Boojin Kim --- diff --git a/drivers/staging/nanohub/Kconfig b/drivers/staging/nanohub/Kconfig index d7cc1155f5f2..2934dccae81d 100644 --- a/drivers/staging/nanohub/Kconfig +++ b/drivers/staging/nanohub/Kconfig @@ -53,4 +53,10 @@ config CONTEXTHUB_DEBUG help Eanble nanohub device debug message +config CONTEXTHUB_DEBUG_MODE + bool "Contexthub reset brings kernel panic" + default N + help + Eanble kernel panic with contexthub FW error + endif # NANOHUB diff --git a/drivers/staging/nanohub/chub.c b/drivers/staging/nanohub/chub.c index e58c8679fe5b..4364779ba75f 100644 --- a/drivers/staging/nanohub/chub.c +++ b/drivers/staging/nanohub/chub.c @@ -203,10 +203,10 @@ static int contexthub_ipc_drv_init(struct contexthub_ipc_info *chub) /* init debug-log */ /* HACK for clang */ - chub->ipc_map->logbuf.eq = 0; - chub->ipc_map->logbuf.dq = 0; + chub->ipc_map->logbuf.logbuf.eq = 0; + chub->ipc_map->logbuf.logbuf.dq = 0; chub->fw_log = log_register_buffer(chub_dev, 0, - (void *)&chub->ipc_map->logbuf, + (void *)&chub->ipc_map->logbuf.logbuf, "fw", 1); if (!chub->fw_log) return -EINVAL; @@ -231,7 +231,7 @@ static int contexthub_ipc_drv_init(struct contexthub_ipc_info *chub) chub->dd_log = log_register_buffer(chub_dev, 1, chub->dd_log_buffer, "dd", 0); #endif - ret = chub_dbg_init(chub); + ret = chub_dbg_init(chub, chub->chub_rt_log.buffer, chub->chub_rt_log.buffer_size); if (ret) dev_err(chub_dev, "%s: fails. ret:%d\n", __func__, ret); @@ -405,7 +405,6 @@ static void contexthub_select_os(struct contexthub_ipc_info *ipc) dev_info(ipc->dev, "%s selected os_name = %s\n", __func__, ipc->os_name); log_flush_all(); - contexthub_download_image(ipc, IPC_REG_OS); ipc_hw_write_shared_reg(AP, ipc->os_load, SR_BOOT_MODE); ipc_write_val(AP, 99); @@ -445,12 +444,31 @@ static void handle_debug_work_func(struct work_struct *work) for (i = 0; i < CHUB_ERR_MAX; i++) { if (ipc->cur_err & (1 << i)) { dev_info(ipc->dev, "%s: loop: err:%d, cur_err:0x%x\n", __func__, i, ipc->cur_err); - handle_debug_work(ipc, i); ipc->cur_err &= ~(1 << i); + handle_debug_work(ipc, i); } } } +static void print_rtlog(struct contexthub_ipc_info *ipc) +{ + if (contexthub_get_token(ipc)) { + pr_info("%s: fails to get token\n", __func__); + atomic_set(&ipc->log_work_active, 0); + return; + } + ipc_logbuf_outprint(&ipc->chub_rt_log); + contexthub_put_token(ipc); +} + +static void handle_log_work_func(struct work_struct *work) +{ + struct contexthub_ipc_info *ipc = + container_of(work, struct contexthub_ipc_info, debug_work); + + print_rtlog(ipc); +} + static inline void clear_err_cnt(struct contexthub_ipc_info *ipc, enum chub_err_type err) { if (ipc->err_cnt[err]) @@ -568,6 +586,7 @@ static int contexthub_hw_reset(struct contexthub_ipc_info *ipc, atomic_set(&ipc->wakeup_chub, CHUB_OFF); atomic_set(&ipc->irq1_apInt, C2A_OFF); atomic_set(&ipc->read_lock.cnt, 0x0); + atomic_set(&ipc->log_work_active, 0); /* chub err init */ for (i = 0; i < CHUB_ERR_MAX; i++) { @@ -754,7 +773,7 @@ int contexthub_ipc_write_event(struct contexthub_ipc_info *ipc, case MAILBOX_EVT_POWER_ON: ret = contexthub_hw_reset(ipc, event); if (!ret) - log_schedule_flush_all(); + log_flush_all(); break; case MAILBOX_EVT_RESET: if (atomic_read(&ipc->chub_status) == CHUB_ST_SHUTDOWN) { @@ -822,8 +841,14 @@ int contexthub_ipc_write_event(struct contexthub_ipc_info *ipc, dev_err(ipc->dev, "%s : chub isn't alive, should be reset. status:%d\n", __func__, atomic_read(&ipc->chub_status)); - atomic_set(&ipc->chub_status, CHUB_ST_NO_RESPONSE); - contexthub_handle_debug(ipc, CHUB_ERR_CHUB_NO_RESPONSE, 0); + if (atomic_read(&ipc->chub_status) == CHUB_ST_POWER_ON) { + atomic_set(&ipc->chub_status, CHUB_ST_NO_RESPONSE); + /* hack don't make panic with chub poweron */ + contexthub_reset(ipc, 1, CHUB_ERR_NONE); + } else { + atomic_set(&ipc->chub_status, CHUB_ST_NO_RESPONSE); + contexthub_handle_debug(ipc, CHUB_ERR_CHUB_NO_RESPONSE, 0); + } ret = -EINVAL; } break; @@ -855,6 +880,9 @@ int contexthub_ipc_write_event(struct contexthub_ipc_info *ipc, /* handle ipc */ switch (event) { + case MAILBOX_EVT_RT_LOGLEVEL: + ipc_logbuf_loglevel(ipc->chub_rt_log.loglevel, 1); + break; case MAILBOX_EVT_ERASE_SHARED: memset(ipc_get_base(IPC_REG_SHARED), 0, ipc_get_offset(IPC_REG_SHARED)); break; @@ -945,6 +973,10 @@ int contexthub_poweron(struct contexthub_ipc_info *ipc) msecs_to_jiffies(WAIT_TIMEOUT_MS)); dev_info(dev, "%s: multi-os poweron %s, ret:%d\n", __func__, atomic_read(&ipc->chub_status) == CHUB_ST_RUN ? "success" : "fails", ret); +#ifdef CONFIG_CONTEXTHUB_DEBUG_MODE + ipc->chub_rt_log.loglevel = 1; +#endif + contexthub_ipc_write_event(ipc, MAILBOX_EVT_RT_LOGLEVEL); } } } else { @@ -991,14 +1023,14 @@ out: return ret; } -int contexthub_reset(struct contexthub_ipc_info *ipc, bool force_load, int dump) +int contexthub_reset(struct contexthub_ipc_info *ipc, bool force_load, enum chub_err_type err) { int ret; int trycnt = 0; - dev_info(ipc->dev, "%s: force:%d, status:%d, in-reset:%d, dump:%d, user:%d\n", + dev_info(ipc->dev, "%s: force:%d, status:%d, in-reset:%d, err:%d, user:%d\n", __func__, force_load, atomic_read(&ipc->chub_status), - atomic_read(&ipc->in_reset), dump, atomic_read(&ipc->in_use_ipc)); + atomic_read(&ipc->in_reset), err, atomic_read(&ipc->in_use_ipc)); mutex_lock(&reset_mutex); if (!force_load && (atomic_read(&ipc->chub_status) == CHUB_ST_RUN)) { mutex_unlock(&reset_mutex); @@ -1020,10 +1052,12 @@ int contexthub_reset(struct contexthub_ipc_info *ipc, bool force_load, int dump) __func__, atomic_read(&ipc->in_use_ipc)); } while (atomic_read(&ipc->in_use_ipc)); - if (dump) { - ipc->err_cnt[CHUB_ERR_NONE] = dump; - chub_dbg_dump_hw(ipc, ipc->cur_err); - } + chub_dbg_dump_hw(ipc, err); + +#ifdef CONFIG_CONTEXTHUB_DEBUG_MODE + if (err) + panic("%s: %d, %d\n", __func__, err, ipc->cur_err); +#endif dev_info(ipc->dev, "%s: start reset status:%d\n", __func__, atomic_read(&ipc->chub_status)); if (!ipc->block_reset) { @@ -1118,6 +1152,9 @@ static void handle_irq(struct contexthub_ipc_info *ipc, enum irq_evt_chub evt) case IRQ_EVT_C2A_INTCLR: atomic_set(&ipc->irq1_apInt, C2A_OFF); break; + case IRQ_EVT_C2A_LOG: + print_rtlog(ipc); + return; default: if (evt < IRQ_EVT_CH_MAX) { int lock; @@ -1135,6 +1172,8 @@ static void handle_irq(struct contexthub_ipc_info *ipc, enum irq_evt_chub evt) } break; }; + if (ipc->chub_rt_log.loglevel) + print_rtlog(ipc); } static irqreturn_t contexthub_irq_handler(int irq, void *data) @@ -1481,7 +1520,7 @@ static ssize_t chub_reset(struct device *dev, const char *buf, size_t count) { struct contexthub_ipc_info *ipc = dev_get_drvdata(dev); - int ret = contexthub_reset(ipc, 1, 1); + int ret = contexthub_reset(ipc, 1, CHUB_ERR_NONE); return ret < 0 ? ret : count; } @@ -1556,6 +1595,7 @@ static int contexthub_ipc_probe(struct platform_device *pdev) chub->data->irq1 = IRQ_EVT_A2C_WAKEUP; chub->data->irq2 = 0; #endif + chub->chub_rt_log.loglevel = 0; atomic_set(&chub->in_use_ipc, 0); atomic_set(&chub->chub_status, CHUB_ST_NO_POWER); atomic_set(&chub->in_reset, 0); @@ -1577,11 +1617,21 @@ static int contexthub_ipc_probe(struct platform_device *pdev) init_waitqueue_head(&chub->read_lock.event); init_waitqueue_head(&chub->chub_alive_lock.event); INIT_WORK(&chub->debug_work, handle_debug_work_func); + INIT_WORK(&chub->log_work, handle_log_work_func); #ifdef CONFIG_EXYNOS_ITMON chub->itmon_nb.notifier_call = chub_itmon_notifier; itmon_notifier_chain_register(&chub->itmon_nb); #endif + /* init fw runtime log */ + chub->chub_rt_log.buffer = vzalloc(SZ_512K); + if (!chub->chub_rt_log.buffer) { + ret = -ENOMEM; + goto err; + } + chub->chub_rt_log.buffer_size = SZ_512K; + chub->chub_rt_log.write_index = 0; + dev_info(chub->dev, "%s with %s FW and %lu clk is done\n", __func__, chub->os_name, chub->clkrate); return 0; diff --git a/drivers/staging/nanohub/chub.h b/drivers/staging/nanohub/chub.h index b5d5ac286848..b6aab7a13dd5 100644 --- a/drivers/staging/nanohub/chub.h +++ b/drivers/staging/nanohub/chub.h @@ -87,6 +87,7 @@ enum mailbox_event { MAILBOX_EVT_CHUB_ALIVE, MAILBOX_EVT_SHUTDOWN, MAILBOX_EVT_RESET, + MAILBOX_EVT_RT_LOGLEVEL, MAILBOX_EVT_MAX, }; @@ -159,6 +160,7 @@ struct contexthub_ipc_info { struct nanohub_platform_data *pdata; wait_queue_head_t wakeup_wait; struct work_struct debug_work; + struct work_struct log_work; struct read_wait read_lock; #ifdef USE_IPC_BUF u8 rxbuf[PACKET_SIZE_MAX]; @@ -177,7 +179,9 @@ struct contexthub_ipc_info { struct log_buffer_info *fw_log; struct log_buffer_info *dd_log; struct LOG_BUFFER *dd_log_buffer; + struct runtimelog_buf chub_rt_log; unsigned long clkrate; + atomic_t log_work_active; atomic_t chub_status; atomic_t in_reset; atomic_t irq1_apInt; @@ -299,7 +303,7 @@ int contexthub_ipc_write(struct contexthub_ipc_info *ipc, uint8_t *tx, int length, int timeout); int contexthub_poweron(struct contexthub_ipc_info *data); int contexthub_download_image(struct contexthub_ipc_info *data, enum ipc_region reg); -int contexthub_reset(struct contexthub_ipc_info *ipc, bool force_load, int dump_id); +int contexthub_reset(struct contexthub_ipc_info *ipc, bool force_load, enum chub_err_type err); int contexthub_wakeup(struct contexthub_ipc_info *data, int evt); int contexthub_request(struct contexthub_ipc_info *ipc); void contexthub_release(struct contexthub_ipc_info *ipc); diff --git a/drivers/staging/nanohub/chub_dbg.c b/drivers/staging/nanohub/chub_dbg.c index 566563a79d87..0c9e57ea76eb 100644 --- a/drivers/staging/nanohub/chub_dbg.c +++ b/drivers/staging/nanohub/chub_dbg.c @@ -62,6 +62,9 @@ static void chub_dbg_dump_gpr(struct contexthub_ipc_info *ipc) i * 4); p_dump->gpr[GPR_PC_INDEX] = readl(ipc->chub_dumpgpr + REG_CHUB_DUMPGPR_PCR); + + for (i = 0; i <= GPR_PC_INDEX; i++) + dev_info(ipc->dev, "%s: %d: 0x%x\n", __func__, i, p_dump->gpr[i]); } } @@ -148,6 +151,7 @@ static void chub_dbg_dump_status(struct contexthub_ipc_info *ipc) #ifdef USE_FW_DUMP contexthub_ipc_write_event(ipc, MAILBOX_EVT_DUMP_STATUS); #endif + ipc_dump(); log_flush(ipc->fw_log); } @@ -232,9 +236,6 @@ static ssize_t chub_bin_sram_read(struct file *file, struct kobject *kobj, struct bin_attribute *battr, char *buf, loff_t off, size_t size) { - struct device *dev = kobj_to_dev(kobj); - - dev_info(dev, "%s(%p: %lld, %zu)\n", __func__, battr->private, off, size); memcpy_fromio(buf, battr->private + off, size); return size; } @@ -258,14 +259,24 @@ static ssize_t chub_bin_dumped_sram_read(struct file *file, struct kobject *kobj return size; } +static ssize_t chub_bin_logbuf_dram_read(struct file *file, struct kobject *kobj, + struct bin_attribute *battr, char *buf, + loff_t off, size_t size) +{ + memcpy(buf, battr->private + off, size); + return size; +} + static BIN_ATTR_RO(chub_bin_sram, 0); static BIN_ATTR_RO(chub_bin_dram, 0); static BIN_ATTR_RO(chub_bin_dumped_sram, 0); +static BIN_ATTR_RO(chub_bin_logbuf_dram, 0); static struct bin_attribute *chub_bin_attrs[] = { &bin_attr_chub_bin_sram, &bin_attr_chub_bin_dram, &bin_attr_chub_bin_dumped_sram, + &bin_attr_chub_bin_logbuf_dram, }; #define SIZE_UTC_NAME (16) @@ -469,6 +480,40 @@ static ssize_t chub_wakeup_store(struct device *dev, return ret ? ret : count; } +static ssize_t chub_loglevel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct contexthub_ipc_info *ipc = dev_get_drvdata(dev); + enum ipc_fw_loglevel loglevel = ipc->chub_rt_log.loglevel; + int index = 0; + + dev_info(dev, "%s: %d\n", __func__, loglevel); + index += sprintf(buf, "%d:%s, %d:%s, %d:%s\n", CHUB_RT_LOG_OFF, "off", CHUB_RT_LOG_DUMP, "dump-only", CHUB_RT_LOG_DUMP_PRT, "dump-prt"); + index += sprintf(buf + index, "cur-loglevel: %d: %s\n", loglevel, !loglevel ? "off" : ((loglevel == CHUB_RT_LOG_DUMP) ? "dump-only" : "dump-prt")); + + return index; +} + +static ssize_t chub_loglevel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct contexthub_ipc_info *ipc = dev_get_drvdata(dev); + long event; + int ret; + + ret = kstrtol(&buf[0], 10, &event); + if (ret) + return ret; + + ipc->chub_rt_log.loglevel = (enum ipc_fw_loglevel)event; + dev_info(dev, "%s: %d->%d\n", __func__, event, ipc->chub_rt_log.loglevel); + contexthub_ipc_write_event(ipc, MAILBOX_EVT_RT_LOGLEVEL); + + return ret ? ret : count; +} + + static struct device_attribute attributes[] = { __ATTR(get_gpr, 0440, chub_get_gpr_show, NULL), __ATTR(dump_status, 0220, NULL, chub_get_dump_status_store), @@ -477,6 +522,7 @@ static struct device_attribute attributes[] = { __ATTR(ipc_test, 0220, NULL, chub_ipc_store), __ATTR(alive, 0440, chub_alive_show, NULL), __ATTR(wakeup, 0220, NULL, chub_wakeup_store), + __ATTR(loglevel, 0664, chub_loglevel_show, chub_loglevel_store), }; void *chub_dbg_get_memory(enum dbg_dump_area area) @@ -501,7 +547,7 @@ void *chub_dbg_get_memory(enum dbg_dump_area area) return addr; } -int chub_dbg_init(struct contexthub_ipc_info *chub) +int chub_dbg_init(struct contexthub_ipc_info *chub, void *kernel_logbuf, int kernel_logbuf_size) { int i, ret = 0; enum dbg_dump_area area; @@ -529,6 +575,9 @@ int chub_dbg_init(struct contexthub_ipc_info *chub) bin_attr_chub_bin_sram.size = ipc_get_chub_mem_size(); bin_attr_chub_bin_sram.private = ipc_get_base(IPC_REG_DUMP); + bin_attr_chub_bin_logbuf_dram.size = kernel_logbuf_size; + bin_attr_chub_bin_logbuf_dram.private = kernel_logbuf; + if (chub_rmem->size < get_dbg_dump_size()) dev_err(dev, "rmem size (%u) should be bigger than dump size(%u)\n", diff --git a/drivers/staging/nanohub/chub_dbg.h b/drivers/staging/nanohub/chub_dbg.h index 27273a5aa9a5..12976e7bf17f 100644 --- a/drivers/staging/nanohub/chub_dbg.h +++ b/drivers/staging/nanohub/chub_dbg.h @@ -21,7 +21,7 @@ enum dbg_dump_area { DBG_AREA_MAX }; -int chub_dbg_init(struct contexthub_ipc_info *chub); +int chub_dbg_init(struct contexthub_ipc_info *chub, void *logbuf, int logbuf_size); void *chub_dbg_get_memory(enum dbg_dump_area area); void chub_dbg_dump_hw(struct contexthub_ipc_info *ipc, enum chub_err_type reason); void chub_dbg_print_hw(struct contexthub_ipc_info *ipc); diff --git a/drivers/staging/nanohub/chub_ipc.c b/drivers/staging/nanohub/chub_ipc.c index 4be436a39014..d640c3b3f386 100644 --- a/drivers/staging/nanohub/chub_ipc.c +++ b/drivers/staging/nanohub/chub_ipc.c @@ -246,9 +246,15 @@ void *ipc_get_chub_map(void) ipc_addr[IPC_REG_RAM].offset = map->ram_end - map->ram_start; ipc_addr[IPC_REG_DUMP].offset = map->dump_end - map->dump_start; + if (ipc_get_offset(IPC_REG_IPC) < sizeof(struct ipc_map_area)) { + CSP_PRINTF_INFO + ("%s: fails. ipc size (0x%x) should be increase to 0x%x\n", + __func__, ipc_get_offset(IPC_REG_IPC), sizeof(struct ipc_map_area)); + return 0; + } + ipc_map = ipc_addr[IPC_REG_IPC].base; - ipc_map->logbuf.size = - ipc_addr[IPC_REG_IPC].offset - sizeof(struct ipc_map_area) - CHUB_PERSISTBUF_SIZE; + ipc_map->logbuf.size = LOGBUF_TOTAL_SIZE; strcpy(&ipc_map->magic[0], CHUB_IPC_MAGIC); ipc_addr[IPC_REG_IPC_EVT_A2C].base = &ipc_map->evt[IPC_EVT_A2C].data; @@ -266,17 +272,14 @@ void *ipc_get_chub_map(void) ipc_addr[IPC_REG_IPC_C2A].offset = sizeof(struct ipc_buf); ipc_addr[IPC_REG_IPC_A2C].offset = sizeof(struct ipc_buf); - ipc_addr[IPC_REG_LOG].base = &ipc_map->logbuf.buf; - ipc_addr[IPC_REG_LOG].offset = ipc_map->logbuf.size; - ipc_addr[IPC_REG_PERSISTBUF].base = ipc_addr[IPC_REG_LOG].base + ipc_addr[IPC_REG_LOG].offset; + /* for rawlevel log */ + ipc_map->logbuf.size = LOGBUF_TOTAL_SIZE; + ipc_map->logbuf.logbuf.size = ipc_addr[IPC_REG_IPC].offset - sizeof(struct ipc_map_area); + /* for runtime log */ + ipc_addr[IPC_REG_LOG].base = &ipc_map->logbuf.log; + ipc_addr[IPC_REG_LOG].offset = ipc_map->logbuf.size + ipc_map->logbuf.logbuf.size; + ipc_addr[IPC_REG_PERSISTBUF].base = &ipc_map->persist; ipc_addr[IPC_REG_PERSISTBUF].offset = CHUB_PERSISTBUF_SIZE; - - if (((u32)ipc_addr[IPC_REG_PERSISTBUF].base + ipc_addr[IPC_REG_PERSISTBUF].offset) > - ((u32)ipc_addr[IPC_REG_IPC].base + ipc_addr[IPC_REG_IPC].offset)) - CSP_PRINTF_INFO("%s: %s: wrong persistbuf addr:%p, %d, ipc_end:0x%x\n", - NAME_PREFIX, __func__, - ipc_addr[IPC_REG_PERSISTBUF].base, ipc_addr[IPC_REG_PERSISTBUF].offset, map->ipc_end); - ipc_addr[IPC_REG_IPC_SENSORINFO].base = &ipc_map->sensormap; ipc_addr[IPC_REG_IPC_SENSORINFO].offset = sizeof(u8) * SENSOR_TYPE_MAX; #ifdef SEOS @@ -284,6 +287,15 @@ void *ipc_get_chub_map(void) CSP_PRINTF_INFO("%s: ipc set sensormap and maic: :%p\n", __func__, &ipc_map->sensormap); memset(&ipc_map->sensormap, 0, sizeof(struct sensor_map)); strcpy(&ipc_map->sensormap.magic[0], SENSORMAP_MAGIC); + /* clear logbuf with 1st booting */ + ipc_map->logbuf.eq = 0; + ipc_map->logbuf.dq = 0; + ipc_map->logbuf.full = 0; + ipc_map->logbuf.dbg_full_cnt = 0; + ipc_map->logbuf.loglevel = 0; + ipc_map->logbuf.logbuf.eq = 0; + ipc_map->logbuf.logbuf.dq = 0; + ipc_map->logbuf.logbuf.full = 0; } #endif @@ -298,15 +310,16 @@ void *ipc_get_chub_map(void) ipc_addr[IPC_REG_DUMP].base, ipc_addr[IPC_REG_DUMP].offset); CSP_PRINTF_INFO - ("%s: ipc_map information\n ipc(%p %d)\n data_c2a(%p %d)\n data_a2c(%p %d)\n evt_c2a(%p %d)\n evt_a2c(%p %d)\n sensormap(%p %d) \n log(%p %d)\n persistbuf(%p %d)\n", - NAME_PREFIX, ipc_get_base(IPC_REG_IPC), ipc_get_offset(IPC_REG_IPC), + ("%s: ipc_map information (0x%x/0x%x)\n ipc(%p %d)\n data_c2a(%p %d)\n data_a2c(%p %d)\n evt_c2a(%p %d)\n evt_a2c(%p %d)\n sensormap(%p %d) \n persistbuf(%p %d)\n log(ch:%p %d / raw:%p %d)\n ", + NAME_PREFIX, sizeof(struct ipc_map_area), ipc_get_offset(IPC_REG_IPC), + ipc_get_base(IPC_REG_IPC), ipc_get_offset(IPC_REG_IPC), ipc_get_base(IPC_REG_IPC_C2A), ipc_get_offset(IPC_REG_IPC_C2A), ipc_get_base(IPC_REG_IPC_A2C), ipc_get_offset(IPC_REG_IPC_A2C), ipc_get_base(IPC_REG_IPC_EVT_C2A), ipc_get_offset(IPC_REG_IPC_EVT_C2A), ipc_get_base(IPC_REG_IPC_EVT_A2C), ipc_get_offset(IPC_REG_IPC_EVT_A2C), ipc_get_base(IPC_REG_IPC_SENSORINFO), ipc_get_offset(IPC_REG_IPC_SENSORINFO), - ipc_get_base(IPC_REG_LOG), ipc_get_offset(IPC_REG_LOG), - ipc_get_base(IPC_REG_PERSISTBUF), ipc_get_offset(IPC_REG_PERSISTBUF)); + ipc_get_base(IPC_REG_PERSISTBUF), ipc_get_offset(IPC_REG_PERSISTBUF), + ipc_get_base(IPC_REG_LOG), ipc_map->logbuf.size, ipc_map->logbuf.logbuf.buf, ipc_map->logbuf.logbuf.size); #ifndef USE_IPC_BUF CSP_PRINTF_INFO @@ -651,8 +664,11 @@ static void ipc_print_logbuf(void) { struct ipc_logbuf *logbuf = &ipc_map->logbuf; - CSP_PRINTF_INFO("%s: token:%d, eq:%d, dq:%d, size:%d, full:%d\n", - NAME_PREFIX, logbuf->token, logbuf->eq, logbuf->dq, logbuf->size, logbuf->full); + CSP_PRINTF_INFO("%s: channel: eq:%d, dq:%d, size:%d, full:%d, dbg_full_cnt:%d, err:%d, fw:%lld, ap:%lld\n", + NAME_PREFIX, logbuf->eq, logbuf->dq, logbuf->size, logbuf->full, logbuf->dbg_full_cnt, + logbuf->errcnt, logbuf->fw_num, logbuf->ap_num); + CSP_PRINTF_INFO("%s: raw: eq:%d, dq:%d, size:%d, full:%d\n", + NAME_PREFIX, logbuf->logbuf.eq, logbuf->logbuf.dq, logbuf->logbuf.size, logbuf->logbuf.full); } int ipc_check_reset_valid() @@ -703,7 +719,6 @@ void ipc_init(void) } ipc_hw_clear_all_int_pend_reg(AP); - for (j = 0; j < IPC_EVT_MAX; j++) { ipc_map->evt[j].ctrl.dq = 0; ipc_map->evt[j].ctrl.eq = 0; @@ -716,6 +731,10 @@ void ipc_init(void) ipc_map->evt[j].data[i].irq = IRQ_EVT_INVAL; } } + ipc_map->logbuf.dbg_full_cnt = 0; + ipc_map->logbuf.errcnt= 0; + ipc_map->logbuf.fw_num = 0; + ipc_map->logbuf.ap_num = 0; } /* evt functions */ @@ -754,6 +773,70 @@ struct ipc_evt_buf *ipc_get_evt(enum ipc_evt_list evtq) #define EVT_WAIT_TIME (5) #define MAX_TRY_CNT (5) +/* ipc_add_evt without lock and print */ +int ipc_add_evt_in_critical(enum ipc_evt_list evtq, enum irq_evt_chub evt) +{ + struct ipc_evt *ipc_evt = &ipc_map->evt[evtq]; + enum ipc_owner owner = (evtq < IPC_EVT_AP_MAX) ? AP : IPC_OWN_MAX; + struct ipc_evt_buf *cur_evt = NULL; + int trycnt = 0; + u32 pending; + + if (!ipc_evt || (owner != AP)) { + return -1; + } + +retry: + if (!__raw_readl(&ipc_evt->ctrl.full)) { + cur_evt = &ipc_evt->data[ipc_evt->ctrl.eq]; + if (!cur_evt) { + return -1; + } + + /* wait pending clear on irq pend */ + pending = ipc_hw_read_gen_int_status_reg(AP, ipc_evt->ctrl.irq); + if (pending) { + /* don't sleep on ap */ + do { + busywait(EVT_WAIT_TIME); + } while (ipc_hw_read_gen_int_status_reg(AP, ipc_evt->ctrl.irq) && (trycnt++ < MAX_TRY_CNT)); + + if (ipc_hw_read_gen_int_status_reg(AP, ipc_evt->ctrl.irq)) { + return -1; + } + } + cur_evt->evt = evt; + cur_evt->status = IPC_EVT_EQ; + cur_evt->irq = ipc_evt->ctrl.irq; + ipc_evt->ctrl.eq = EVT_Q_INT(ipc_evt->ctrl.eq + 1); + ipc_evt->ctrl.irq = IRQ_EVT_IDX_INT(ipc_evt->ctrl.irq + 1); + if (ipc_evt->ctrl.eq == __raw_readl(&ipc_evt->ctrl.dq)) + __raw_writel(1, &ipc_evt->ctrl.full); + } else { + do { + busywait(EVT_WAIT_TIME); + } while (ipc_evt->ctrl.full && (trycnt++ < MAX_TRY_CNT)); + + if (!__raw_readl(&ipc_evt->ctrl.full)) { + goto retry; + } else { + ipc_dump(); + return -1; + } + } + + if (owner != IPC_OWN_MAX) { +#if defined(AP_IPC) + ipc_write_val(AP, sched_clock()); +#endif + if (cur_evt) + ipc_hw_gen_interrupt(owner, cur_evt->irq); + else + return -1; + } + return 0; +} + int ipc_add_evt(enum ipc_evt_list evtq, enum irq_evt_chub evt) { struct ipc_evt *ipc_evt = &ipc_map->evt[evtq]; @@ -812,7 +895,7 @@ retry: if (!__raw_readl(&ipc_evt->ctrl.full)) { CSP_PRINTF_INFO("%s: %s: evt %d during %d ms is full\n", - NAME_PREFIX, __func__, evt, EVT_WAIT_TIME * trycnt); + NAME_PREFIX, __func__, evt, EVT_WAIT_TIME * trycnt); goto retry; } else { CSP_PRINTF_ERROR("%s: %s: fail to add evt by full\n", NAME_PREFIX, __func__); @@ -872,39 +955,151 @@ void ipc_dump(void) ipc_print_logbuf(); } -u32 ipc_logbuf_get_token(void) +#ifdef CHUB_IPC +void ipc_logbuf_put_with_char(char ch) { - __raw_writel(ipc_map->logbuf.token + 1, &ipc_map->logbuf.token); + if (ipc_map) { + struct logbuf_raw *logbuf = &ipc_map->logbuf.logbuf; + + if (logbuf->size) { + char *buf = (char *)&logbuf->buf[0]; - return __raw_readl(&ipc_map->logbuf.token); + *(buf + logbuf->eq) = ch; + logbuf->eq = (logbuf->eq + 1) % logbuf->size; +#ifdef IPC_DEBUG + if (logbuf->eq == logbuf->dq) { + ipc_write_debug_event(AP, IPC_DEBUG_CHUB_FULL_LOG); + ipc_add_evt(IPC_EVT_C2A, IRQ_EVT_CHUB_TO_AP_DEBUG); + } +#endif + } + } } -void ipc_logbuf_put_with_char(char ch) +void *ipc_logbuf_inbase(bool force) { - char *logbuf; - int eqNext; - if (ipc_map) { - eqNext = ipc_map->logbuf.eq + 1; + struct ipc_logbuf *logbuf = &ipc_map->logbuf; -#ifdef IPC_DEBUG - if (eqNext == ipc_map->logbuf.dq) { - ipc_write_debug_event(AP, IPC_DEBUG_CHUB_FULL_LOG); - ipc_add_evt(IPC_EVT_C2A, IRQ_EVT_CHUB_TO_AP_DEBUG); + if (force || logbuf->loglevel) { + struct logbuf_content *log; + int index; + + DISABLE_IRQ(); + if (logbuf->full) /* logbuf is full overwirte */ + logbuf->dbg_full_cnt++; + + index = logbuf->eq; + logbuf->eq = (logbuf->eq + 1) % LOGBUF_NUM; + if (logbuf->eq == logbuf->dq) + logbuf->full = 1; + ENABLE_IRQ(); + + log = &logbuf->log[index]; + memset(log, 0, sizeof(struct logbuf_content)); + return log; } + } + return NULL; +} + +void ipc_logbuf_req_flush(struct logbuf_content *log, bool force) +{ + if (log) { + struct ipc_logbuf *logbuf = &ipc_map->logbuf; + + /* debug check overwrite */ + log->size = logbuf->fw_num++; + if (ipc_map) { + u32 eq = logbuf->eq; + u32 dq = logbuf->dq; + u32 logcnt = (eq >= dq) ? (eq - dq) : (eq + (logbuf->size - dq)); + + if (((ipc_get_ap_wake() == AP_WAKE) && (logcnt > LOGBUF_FLUSH_THRESHOLD)) || force) { + DISABLE_IRQ(); + if (!logbuf->flush_req) { + logbuf->flush_req = 1; + ipc_add_evt_in_critical(IPC_EVT_C2A, IRQ_EVT_C2A_LOG); + } + ENABLE_IRQ(); + } + } + } +} +#else +#define ipc_logbuf_put_with_char(a) ((void)0) +#define ipc_logbuf_inbase(a) ((void)0) +#define ipc_logbuf_req_flush(a, c) ((void)0) #endif - ipc_map->logbuf.token++; - logbuf = ipc_map->logbuf.buf; - *(logbuf + ipc_map->logbuf.eq) = ch; +#ifdef AP_IPC +void ipc_logbuf_outprint(struct runtimelog_buf *rt_buf) +{ + if (ipc_map) { + struct logbuf_content *log; + struct ipc_logbuf *logbuf = &ipc_map->logbuf; + int eq; + int retrycnt = 0; - if (eqNext == ipc_map->logbuf.size) - ipc_map->logbuf.eq = 0; - else - ipc_map->logbuf.eq = eqNext; +retry: + eq = logbuf->eq; + if (logbuf->full) { + logbuf->full = 0; + logbuf->dq = logbuf->eq; + } + + while (eq != logbuf->dq) { + log = &logbuf->log[logbuf->dq]; + + /* debug check overwrite */ + if (logbuf->ap_num != log->size) { + logbuf->ap_num = log->size; + logbuf->errcnt++; + } + logbuf->ap_num++; + + if (logbuf->loglevel == CHUB_RT_LOG_DUMP_PRT) + CSP_PRINTF_INFO("%s: %s", NAME_PREFIX, (char *)log); + + if (rt_buf) { + int len = strlen((char *)log); + + if (rt_buf->write_index + len > rt_buf->buffer_size) + rt_buf->write_index = 0; + memcpy(rt_buf->buffer + rt_buf->write_index, (char *)log, len); + rt_buf->write_index += len; + } + logbuf->dq = (logbuf->dq + 1) % LOGBUF_NUM; + } + + if ((eq != logbuf->eq) && !retrycnt) { + CSP_PRINTF_INFO("%s: retry: flush:%d, cnt:%d, eq:%d->%d, dq:%d\n", + NAME_PREFIX, logbuf->flush_req, logbuf->dbg_full_cnt, eq, logbuf->eq, logbuf->dq); + goto retry; + } + + if (logbuf->flush_req) + logbuf->flush_req = 0; } } +enum ipc_fw_loglevel ipc_logbuf_loglevel(enum ipc_fw_loglevel loglevel, int set) +{ + if (ipc_map) { + struct ipc_logbuf *logbuf = &ipc_map->logbuf; + + if (set) + logbuf->loglevel = (u8)loglevel; + return (enum ipc_fw_loglevel)logbuf->loglevel; + } + + return 0; +} +#else +#define ipc_logbuf_outprint(a) ((void)0) +#define ipc_logbuf_loglevel(a, b) ((void)0) +#endif + void ipc_set_owner(enum ipc_owner owner, void *base, enum ipc_direction dir) { ipc_own[owner].base = base; diff --git a/drivers/staging/nanohub/chub_ipc.h b/drivers/staging/nanohub/chub_ipc.h index b19c3a8a6b32..f88689340c7d 100644 --- a/drivers/staging/nanohub/chub_ipc.h +++ b/drivers/staging/nanohub/chub_ipc.h @@ -18,7 +18,7 @@ #define AP_IPC #endif -#define IPC_VERSION (181024) +#define IPC_VERSION (181213) #if defined(CHUB_IPC) #if defined(SEOS) @@ -117,7 +117,6 @@ struct chub_bootargs { */ #define IPC_BUF_NUM (IRQ_EVT_CH_MAX) #define IPC_EVT_NUM (30) -#define IPC_LOGBUF_NUM (256) enum sr_num { SR_0 = 0, @@ -160,6 +159,7 @@ enum irq_evt_chub { IRQ_EVT_C2A_ASSERT, IRQ_EVT_C2A_INT, IRQ_EVT_C2A_INTCLR, + IRQ_EVT_C2A_LOG, IRQ_EVT_CHUB_EVT_MAX = 15, IRQ_EVT_CHUB_ALIVE = IRQ_EVT_CHUB_EVT_MAX, IRQ_EVT_CHUB_MAX = 16, /* max irq number on mailbox */ @@ -319,13 +319,53 @@ struct ipc_log_content { u8 buffer[sizeof(u64) + HOSTINTF_SENSOR_DATA_MAX - sizeof(u32)]; }; +#define LOGBUF_TOTAL_SIZE (LOGBUF_SIZE * LOGBUF_NUM) +#define LOGBUF_SIZE (64) +#define LOGBUF_NUM (80) +#define LOGBUF_DATA_SIZE (LOGBUF_SIZE - sizeof(u64)) +#define LOGBUF_FLUSH_THRESHOLD (LOGBUF_NUM / 4) + +struct logbuf_content{ + char buf[LOGBUF_DATA_SIZE]; + u64 size; +}; + +struct logbuf_raw { + u32 eq; /* write owner chub (index_writer) */ + u32 dq; /* read onwer ap (index_reader) */ + u32 size; + u32 full; + char buf[0]; +}; + +enum ipc_fw_loglevel { + CHUB_RT_LOG_OFF, + CHUB_RT_LOG_DUMP, + CHUB_RT_LOG_DUMP_PRT, +}; + +struct runtimelog_buf { + char *buffer; + unsigned int buffer_size; + unsigned int write_index; + enum ipc_fw_loglevel loglevel; +}; + struct ipc_logbuf { + struct logbuf_content log[LOGBUF_NUM]; u32 eq; /* write owner chub (index_writer) */ u32 dq; /* read onwer ap (index_reader) */ u32 size; - u32 token; - u32 full; - char buf[0]; + u8 dbg_full_cnt; + u8 full; + u8 flush_req; + u8 loglevel; + /* for debug */ + int errcnt; + u64 fw_num; + u64 ap_num; + /* rawlevel logout */ + struct logbuf_raw logbuf; }; #ifndef IPC_DATA_SIZE @@ -428,6 +468,7 @@ struct ipc_map_area { struct ipc_evt evt[IPC_EVT_MAX]; struct ipc_debug dbg; struct sensor_map sensormap; + char persist[CHUB_PERSISTBUF_SIZE]; struct ipc_logbuf logbuf; }; @@ -500,11 +541,14 @@ int ipc_check_reset_valid(void); void ipc_init(void); int ipc_hw_read_int_start_index(enum ipc_owner owner); /* logbuf functions */ -void *ipc_get_logbuf(void); -unsigned int ipc_logbuf_get_token(void); +enum ipc_fw_loglevel ipc_logbuf_loglevel(enum ipc_fw_loglevel loglevel, int set); +void *ipc_logbuf_inbase(bool force); +void ipc_logbuf_outprint(struct runtimelog_buf *rt_buf); +void ipc_logbuf_req_flush(struct logbuf_content *log, bool force); /* evt functions */ struct ipc_evt_buf *ipc_get_evt(enum ipc_evt_list evt); int ipc_add_evt(enum ipc_evt_list evt, enum irq_evt_chub irq); +int ipc_add_evt_in_critical(enum ipc_evt_list evtq, enum irq_evt_chub evt); void ipc_print_evt(enum ipc_evt_list evt); /* mailbox hw access */ void ipc_set_owner(enum ipc_owner owner, void *base, enum ipc_direction dir); @@ -520,7 +564,6 @@ void ipc_hw_set_mcuctrl(enum ipc_owner owner, unsigned int val); void ipc_hw_mask_irq(enum ipc_owner owner, int irq); void ipc_hw_unmask_irq(enum ipc_owner owner, int irq); void ipc_logbuf_put_with_char(char ch); -int ipc_logbuf_need_flush(void); void ipc_write_debug_event(enum ipc_owner owner, enum ipc_debug_event action); u32 ipc_read_debug_event(enum ipc_owner owner); void ipc_write_debug_val(enum ipc_data_list dir, u32 val); diff --git a/drivers/staging/nanohub/chub_log.c b/drivers/staging/nanohub/chub_log.c index 8acc05bc6a2c..35c507462459 100644 --- a/drivers/staging/nanohub/chub_log.c +++ b/drivers/staging/nanohub/chub_log.c @@ -23,7 +23,7 @@ #include "chub_ipc.h" #ifdef CONFIG_CONTEXTHUB_DEBUG -#define SIZE_OF_BUFFER (SZ_512K + SZ_128K) +#define SIZE_OF_BUFFER (SZ_128K + SZ_128K) #else #define SIZE_OF_BUFFER (SZ_128K) #endif @@ -114,11 +114,10 @@ void log_flush(struct log_buffer_info *info) unsigned int index_writer = buffer->index_writer; /* check logbuf index dueto sram corruption */ - if ((buffer->index_reader >= ipc_get_offset(IPC_REG_LOG)) - || (buffer->index_writer >= ipc_get_offset(IPC_REG_LOG))) { - dev_err(info->dev, "%s(%d): offset is corrupted. index_writer=%u, index_reader=%u, size=%u-%u\n", - __func__, info->id, buffer->index_writer, buffer->index_reader, buffer->size, - ipc_get_offset(IPC_REG_LOG)); + if ((buffer->index_reader >= buffer->size) + || (buffer->index_writer >= buffer->size)) { + dev_err(info->dev, "%s(%d): offset is corrupted. index_writer=%u, index_reader=%u, size=%u\n", + __func__, info->id, buffer->index_writer, buffer->index_reader, buffer->size); return; } @@ -369,11 +368,10 @@ static void log_dump(struct log_buffer_info *info, int err) u32 wrap_index = buffer->index_writer; /* check logbuf index dueto sram corruption */ - if ((buffer->index_reader >= ipc_get_offset(IPC_REG_LOG)) - || (buffer->index_writer >= ipc_get_offset(IPC_REG_LOG))) { - dev_err(info->dev, "%s(%d): offset is corrupted. index_writer=%u, index_reader=%u, size=%u-%u\n", - __func__, info->id, buffer->index_writer, buffer->index_reader, buffer->size, - ipc_get_offset(IPC_REG_LOG)); + if ((buffer->index_reader >= buffer->size) + || (buffer->index_writer >= buffer->size)) { + dev_err(info->dev, "%s(%d): offset is corrupted. index_writer=%u, index_reader=%u, size=%u\n", + __func__, info->id, buffer->index_writer, buffer->index_reader, buffer->size); return; } @@ -458,22 +456,19 @@ static ssize_t chub_log_flush_save(struct device *dev, err = kstrtol(&buf[0], 10, &event); if (!err) { - if (!auto_log_flush_ms) { - if (!err) { - log_flush_all(); - } else { - pr_err("%s: fails to flush log\n", __func__); - } + if (!event) { + log_flush_all(); + } else { + /* update log_flush time */ + auto_log_flush_ms = event; + pr_err("%s: set flush ms:%d\n", __func__, auto_log_flush_ms); + schedule_delayed_work(&log_flush_all_work, msecs_to_jiffies(auto_log_flush_ms)); } - /* update log_flush time */ - auto_log_flush_ms = event * 1000; - return count; } else { + pr_err("%s: fails event:%d, err:%d\n", __func__, event, err); return 0; } - - return count; } static ssize_t chub_dump_log_save(struct device *dev, @@ -508,6 +503,7 @@ struct log_buffer_info *log_register_buffer(struct device *dev, int id, info->id = id; info->file_created = false; info->kernel_buffer.buffer = vzalloc(SIZE_OF_BUFFER); + info->kernel_buffer.buffer_size = SIZE_OF_BUFFER; info->kernel_buffer.index = 0; info->kernel_buffer.index_reader = 0; info->kernel_buffer.index_writer = 0; diff --git a/drivers/staging/nanohub/chub_log.h b/drivers/staging/nanohub/chub_log.h index 32e6f206db06..d8d4ac85eb5b 100644 --- a/drivers/staging/nanohub/chub_log.h +++ b/drivers/staging/nanohub/chub_log.h @@ -11,9 +11,11 @@ #define __CHUB_LOG_H_ #include +#include "chub_ipc.h" struct log_kernel_buffer { char *buffer; + unsigned int buffer_size; unsigned int index; bool wrap; volatile bool updated; @@ -42,7 +44,6 @@ struct LOG_BUFFER { volatile u32 index_writer; volatile u32 index_reader; volatile u32 size; - volatile u32 token; volatile u32 full; char buffer[0]; }; diff --git a/drivers/staging/nanohub/main.c b/drivers/staging/nanohub/main.c index d350cad7b2b2..36867bfc726c 100644 --- a/drivers/staging/nanohub/main.c +++ b/drivers/staging/nanohub/main.c @@ -885,7 +885,7 @@ static ssize_t nanohub_download_bl(struct device *dev, return ret < 0 ? ret : count; #elif defined(CONFIG_NANOHUB_MAILBOX) - ret = contexthub_reset(data->pdata->mailbox_client, 1, 0); + ret = contexthub_reset(data->pdata->mailbox_client, 1, CHUB_ERR_NONE); return ret < 0 ? ret : count; #endif