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
/* 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;
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);
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);
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])
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++) {
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) {
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;
/* 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;
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 {
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);
__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) {
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;
}
break;
};
+ if (ipc->chub_rt_log.loglevel)
+ print_rtlog(ipc);
}
static irqreturn_t contexthub_irq_handler(int irq, void *data)
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;
}
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);
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;
MAILBOX_EVT_CHUB_ALIVE,
MAILBOX_EVT_SHUTDOWN,
MAILBOX_EVT_RESET,
+ MAILBOX_EVT_RT_LOGLEVEL,
MAILBOX_EVT_MAX,
};
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];
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;
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);
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]);
}
}
#ifdef USE_FW_DUMP
contexthub_ipc_write_event(ipc, MAILBOX_EVT_DUMP_STATUS);
#endif
+ ipc_dump();
log_flush(ipc->fw_log);
}
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;
}
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)
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),
__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)
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;
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",
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);
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;
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
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
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
{
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()
}
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;
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 */
#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];
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__);
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;
#define AP_IPC
#endif
-#define IPC_VERSION (181024)
+#define IPC_VERSION (181213)
#if defined(CHUB_IPC)
#if defined(SEOS)
*/
#define IPC_BUF_NUM (IRQ_EVT_CH_MAX)
#define IPC_EVT_NUM (30)
-#define IPC_LOGBUF_NUM (256)
enum sr_num {
SR_0 = 0,
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 */
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
struct ipc_evt evt[IPC_EVT_MAX];
struct ipc_debug dbg;
struct sensor_map sensormap;
+ char persist[CHUB_PERSISTBUF_SIZE];
struct ipc_logbuf logbuf;
};
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);
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);
#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
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;
}
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;
}
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,
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;
#define __CHUB_LOG_H_
#include <linux/device.h>
+#include "chub_ipc.h"
struct log_kernel_buffer {
char *buffer;
+ unsigned int buffer_size;
unsigned int index;
bool wrap;
volatile bool updated;
volatile u32 index_writer;
volatile u32 index_reader;
volatile u32 size;
- volatile u32 token;
volatile u32 full;
char buffer[0];
};
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