}
}
-static void request_debug_work(struct contexthub_ipc_info *ipc,
+static void contexthub_handle_debug(struct contexthub_ipc_info *ipc,
enum chub_err_type err, bool enable_wq)
{
dev_info(ipc->dev, "%s: err:%d(cnt:%d), enable_wq:%d\n",
return ret;
fail_get_channel:
- request_debug_work(ipc, CHUB_ERR_READ_FAIL, 0);
+ contexthub_handle_debug(ipc, CHUB_ERR_READ_FAIL, 0);
return -EINVAL;
}
if (ret) {
pr_err("%s: fails to write data: ret:%d, len:%d errcnt:%d\n",
__func__, ret, length, ipc->err_cnt[CHUB_ERR_WRITE_FAIL]);
- request_debug_work(ipc, CHUB_ERR_WRITE_FAIL, 0);
+ contexthub_handle_debug(ipc, CHUB_ERR_WRITE_FAIL, 0);
length = 0;
} else {
clear_err_cnt(ipc, CHUB_ERR_WRITE_FAIL);
"%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);
- request_debug_work(ipc, CHUB_ERR_CHUB_NO_RESPONSE, 0);
+ contexthub_handle_debug(ipc, CHUB_ERR_CHUB_NO_RESPONSE, 0);
ret = -EINVAL;
}
break;
break;
}
- if (!need_ipc)
- return ret;
-
- if (contexthub_get_token(ipc)) {
- dev_warn(ipc->dev, "%s event:%d/%d fails chub isn't active, status:%d, inreset:%d\n",
- __func__, event, MAILBOX_EVT_MAX, atomic_read(&ipc->chub_status), atomic_read(&ipc->in_reset));
- return -EINVAL;
- }
-
- /* handle ipc */
- switch (event) {
- case MAILBOX_EVT_ERASE_SHARED:
- memset(ipc_get_base(IPC_REG_SHARED), 0, ipc_get_offset(IPC_REG_SHARED));
- break;
- case MAILBOX_EVT_DUMP_STATUS:
- /* dump nanohub kernel status */
- dev_info(ipc->dev, "Request to dump chub fw status\n");
- ipc_write_debug_event(AP, (u32)MAILBOX_EVT_DUMP_STATUS);
- ipc_add_evt(IPC_EVT_A2C, IRQ_EVT_A2C_DEBUG);
- break;
- case MAILBOX_EVT_WAKEUP_CLR:
- if (atomic_read(&ipc->wakeup_chub) == CHUB_ON) {
- atomic_set(&ipc->wakeup_chub, CHUB_OFF);
- ipc_add_evt(IPC_EVT_A2C, IRQ_EVT_A2C_WAKEUP_CLR);
- }
- break;
- case MAILBOX_EVT_WAKEUP:
- if (atomic_read(&ipc->wakeup_chub) == CHUB_OFF) {
- atomic_set(&ipc->wakeup_chub, CHUB_ON);
- ipc_add_evt(IPC_EVT_A2C, IRQ_EVT_A2C_WAKEUP);
+ if (need_ipc) {
+ if (contexthub_get_token(ipc)) {
+ dev_warn(ipc->dev, "%s event:%d/%d fails chub isn't active, status:%d, inreset:%d\n",
+ __func__, event, MAILBOX_EVT_MAX, atomic_read(&ipc->chub_status), atomic_read(&ipc->in_reset));
+ return -EINVAL;
}
- break;
- default:
- /* handle ipc utc */
- if ((int)event < IPC_DEBUG_UTC_MAX) {
- ipc->utc_run = event;
- if ((int)event == IPC_DEBUG_UTC_TIME_SYNC)
- check_rtc_time();
- ipc_write_debug_event(AP, (u32)event);
- ipc_add_evt(IPC_EVT_A2C, IRQ_EVT_A2C_DEBUG);
- ret = 0;
+
+ /* handle ipc */
+ switch (event) {
+ case MAILBOX_EVT_ERASE_SHARED:
+ memset(ipc_get_base(IPC_REG_SHARED), 0, ipc_get_offset(IPC_REG_SHARED));
+ break;
+ case MAILBOX_EVT_DUMP_STATUS:
+ /* dump nanohub kernel status */
+ dev_info(ipc->dev, "Request to dump chub fw status\n");
+ ipc_write_debug_event(AP, (u32)MAILBOX_EVT_DUMP_STATUS);
+ ret = ipc_add_evt(IPC_EVT_A2C, IRQ_EVT_A2C_DEBUG);
+ break;
+ case MAILBOX_EVT_WAKEUP_CLR:
+ if (atomic_read(&ipc->wakeup_chub) == CHUB_ON) {
+ atomic_set(&ipc->wakeup_chub, CHUB_OFF);
+ ret = ipc_add_evt(IPC_EVT_A2C, IRQ_EVT_A2C_WAKEUP_CLR);
+ }
+ break;
+ case MAILBOX_EVT_WAKEUP:
+ if (atomic_read(&ipc->wakeup_chub) == CHUB_OFF) {
+ atomic_set(&ipc->wakeup_chub, CHUB_ON);
+ ret = ipc_add_evt(IPC_EVT_A2C, IRQ_EVT_A2C_WAKEUP);
+ }
+ break;
+ default:
+ /* handle ipc utc */
+ if ((int)event < IPC_DEBUG_UTC_MAX) {
+ ipc->utc_run = event;
+ if ((int)event == IPC_DEBUG_UTC_TIME_SYNC)
+ check_rtc_time();
+ ipc_write_debug_event(AP, (u32)event);
+ ret = ipc_add_evt(IPC_EVT_A2C, IRQ_EVT_A2C_DEBUG);
+ }
+ break;
}
- break;
+ contexthub_put_token(ipc);
+
+ if (ret)
+ ipc->err_cnt[CHUB_ERR_EVTQ_ADD]++;
}
- contexthub_put_token(ipc);
return ret;
}
} else {
ret = -EINVAL;
}
-
return ret;
}
dev_info(ipc->dev, "%s: wait for ipc user free: %d\n", __func__, atomic_read(&ipc->in_use_ipc));
} while (atomic_read(&ipc->in_use_ipc));
- if (dump)
+ if (dump) {
+ ipc->err_cnt[CHUB_ERR_NONE] = dump;
chub_dbg_dump_hw(ipc, ipc->cur_err);
+ }
dev_info(ipc->dev, "%s: start reset status:%d\n", __func__, atomic_read(&ipc->chub_status));
if (!ipc->block_reset) {
const struct firmware *entry;
int ret;
- dev_info(ipc->dev, "%s: enter for bl:%d\n", reg == IPC_REG_BL);
+ dev_info(ipc->dev, "%s: enter for bl:%d\n", __func__, reg == IPC_REG_BL);
if (reg == IPC_REG_BL)
ret = request_firmware(&entry, "bl.unchecked.bin", ipc->dev);
else if (reg == IPC_REG_OS)
{
switch (evt) {
case IRQ_EVT_C2A_DEBUG:
- request_debug_work(ipc, CHUB_ERR_NANOHUB, 1);
+ contexthub_handle_debug(ipc, CHUB_ERR_NANOHUB, 1);
break;
case IRQ_EVT_C2A_INT:
if (atomic_read(&ipc->irq1_apInt) == C2A_OFF) {
status, ipc_hw_read_int_status_reg(AP),
ipc_hw_read_int_gen_reg(AP));
ipc_hw_clear_all_int_pend_reg(AP);
- request_debug_work(ipc, err, 1);
+ contexthub_handle_debug(ipc, err, 1);
} else {
clear_err_cnt(ipc, CHUB_ERR_EVTQ_EMTPY);
clear_err_cnt(ipc, CHUB_ERR_EVTQ_NO_HW_TRIGGER);
dev_info(ipc->dev, "%s called\n", __func__);
disable_irq_nosync(ipc->irq_wdt);
ipc->irq_wdt_disabled = 1;
- request_debug_work(ipc, CHUB_ERR_FW_WDT, 1);
+ contexthub_handle_debug(ipc, CHUB_ERR_FW_WDT, 1);
return IRQ_HANDLED;
}
(!strncmp("PDMA_SHUB", itmon_data->master, sizeof("PDMA_SHUB") - 1)))) {
dev_info(data->dev, "%s: chub(%s) itmon detected: action:%d!!\n",
__func__, itmon_data->master, action);
- request_debug_work(data, CHUB_ERR_ITMON, 1);
+ contexthub_handle_debug(data, CHUB_ERR_ITMON, 1);
return NOTIFY_OK;
}
static int contexthub_suspend(struct device *dev)
{
struct contexthub_ipc_info *ipc = dev_get_drvdata(dev);
+#ifdef CONFIG_CHRE_SENSORHUB_HAL
struct nanohub_data *data = ipc->data;
+#endif
+
+ if (atomic_read(&ipc->chub_status) != CHUB_ST_RUN)
+ return 0;
- pr_info("nanohub log to kernel off\n");
- ipc_set_chub_kernel_log(KERNEL_LOG_OFF);
+ dev_dbg(dev, "nanohub log to kernel off\n");
+ ipc_hw_write_shared_reg(AP, MAILBOX_REQUEST_KLOG_OFF, SR_3);
+ ipc_hw_gen_interrupt(AP, IRQ_EVT_CHUB_ALIVE);
+#ifdef CONFIG_CHRE_SENSORHUB_HAL
return nanohub_suspend(data->iio_dev);
+#else
+ return 0;
+#endif
}
static int contexthub_resume(struct device *dev)
{
struct contexthub_ipc_info *ipc = dev_get_drvdata(dev);
+#ifdef CONFIG_CHRE_SENSORHUB_HAL
struct nanohub_data *data = ipc->data;
+#endif
- pr_info("nanohub log to kernel on\n");
- ipc_set_chub_kernel_log(KERNEL_LOG_ON);
+ if (atomic_read(&ipc->chub_status) != CHUB_ST_RUN)
+ return 0;
+ dev_dbg(dev, "nanohub log to kernel on\n");
+ ipc_hw_write_shared_reg(AP, MAILBOX_REQUEST_KLOG_ON, SR_3);
+ ipc_hw_gen_interrupt(AP, IRQ_EVT_CHUB_ALIVE);
+
+#ifdef CONFIG_CHRE_SENSORHUB_HAL
return nanohub_resume(data->iio_dev);
+#else
+ return 0;
+#endif
}
static SIMPLE_DEV_PM_OPS(contexthub_pm_ops, contexthub_suspend, contexthub_resume);
#if defined(SEOS)
#include <seos.h>
#include <errno.h>
+#include <cmsis.h>
#elif defined(EMBOS)
#include <Device.h>
#define EINVAL 22
return ipc_map;
}
+#ifdef CHUB_IPC
+#define DISABLE_IRQ() __disable_irq();
+#define ENABLE_IRQ() __enable_irq();
+static inline void busywait(u32 ms)
+{
+ msleep(ms);
+}
+#else /* AP IPC doesn't need it */
+#define DISABLE_IRQ() do {} while(0)
+#define ENABLE_IRQ() do {} while(0)
+static inline void busywait(u32 ms)
+{
+ (void)ms;
+ cpu_relax();
+}
+#endif
+
#ifndef USE_IPC_BUF
static inline bool __ipc_queue_empty(struct ipc_buf *ipc_data)
{
struct ipc_buf *ipc_data = ipc_get_base(reg);
if (length <= PACKET_SIZE_MAX) {
+ DISABLE_IRQ();
if (!__ipc_queue_full(ipc_data)) {
struct ipc_channel_buf *ipc;
CSP_PRINTF_INFO("%s: %s: is full\n", NAME_PREFIX, __func__);
ret = -EINVAL;
}
+ ENABLE_IRQ();
} else {
CSP_PRINTF_INFO("%s: %s: invalid size:%d\n",
NAME_PREFIX, __func__, length);
enum ipc_evt_list evtq = (dir == IPC_DATA_C2A) ? IPC_EVT_C2A : IPC_EVT_A2C;
ret = ipc_add_evt(evtq, IRQ_EVT_CH0);
+ if (ret)
+ CSP_PRINTF_INFO("%s: %s: fail by add_evt\n",
+ NAME_PREFIX, __func__);
} else {
CSP_PRINTF_INFO("%s: %s: error: eq:%d, dq:%d\n",
NAME_PREFIX, __func__, ipc_data->eq, ipc_data->dq);
+ ipc_dump();
}
return ret;
}
{
enum ipc_region reg = (dir == IPC_DATA_C2A) ? IPC_REG_IPC_C2A : IPC_REG_IPC_A2C;
struct ipc_buf *ipc_data = ipc_get_base(reg);
+ void *buf = NULL;
+ DISABLE_IRQ();
if (!__ipc_queue_empty(ipc_data)) {
struct ipc_channel_buf *ipc;
ipc = &ipc_data->ch[ipc_data->dq];
*len = ipc->size;
ipc_data->dq = (ipc_data->dq + 1) % IPC_CH_BUF_NUM;
- return ipc->buf;
+ buf = ipc->buf;
}
-
- return NULL;
+ ENABLE_IRQ();
+ return buf;
}
#else
static inline void ipc_copy_bytes(u8 *dst, u8 *src, int size)
struct ipc_evt *ipc_evt = &ipc_map->evt[evtq];
struct ipc_evt_buf *cur_evt = NULL;
+ DISABLE_IRQ();
if (ipc_evt->ctrl.dq != __raw_readl(&ipc_evt->ctrl.eq)) {
cur_evt = &ipc_evt->data[ipc_evt->ctrl.dq];
cur_evt->status = IPC_EVT_DQ;
ipc_evt->ctrl.dq = EVT_Q_INT(ipc_evt->ctrl.dq + 1);
__raw_writel(0, &ipc_evt->ctrl.full);
}
+ ENABLE_IRQ();
return cur_evt;
}
-#define EVT_WAIT_TIME (10)
+#define EVT_WAIT_TIME (5)
#define MAX_TRY_CNT (5)
int ipc_add_evt(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;
-#if defined(CHUB_IPC)
int trycnt = 0;
-#endif
+ u32 pending;
if (!ipc_evt || (owner != AP)) {
CSP_PRINTF_ERROR("%s: %s: invalid ipc_evt, owner:%d\n", NAME_PREFIX, __func__, owner);
return -1;
}
-#if 0
- /* check index due to sram corruption */
- if ((__raw_readl(&ipc_evt->ctrl.eq) > IPC_EVT_NUM) ||
- (__raw_readl(&ipc_evt->ctrl.dq) > IPC_EVT_NUM) ||
- (__raw_readl(&ipc_evt->ctrl.full) > 1) ||
- (__raw_readl(&ipc_evt->ctrl.empty) > 1)) {
- CSP_PRINTF_ERROR("%s: invalid index: eq:%d, dq:%d, full:%d, empty:%d\n",
- __func__, ipc_evt->ctrl.eq, ipc_evt->ctrl.dq,
- ipc_evt->ctrl.full, ipc_evt->ctrl.empty);
- return -1;
- }
-#endif
+retry:
+ DISABLE_IRQ();
if (!__raw_readl(&ipc_evt->ctrl.full)) {
cur_evt = &ipc_evt->data[ipc_evt->ctrl.eq];
if (!cur_evt) {
CSP_PRINTF_ERROR("%s: invalid cur_evt\n", __func__);
+ ENABLE_IRQ();
return -1;
}
/* wait pending clear on irq pend */
- if (ipc_hw_read_gen_int_status_reg(AP, ipc_evt->ctrl.irq)) {
- CSP_PRINTF_ERROR("%s: irq:%d pending:0x%x\n", __func__, ipc_evt->ctrl.irq, ipc_hw_read_int_status_reg(AP));
-#if defined(CHUB_IPC)
+ pending = ipc_hw_read_gen_int_status_reg(AP, ipc_evt->ctrl.irq);
+ if (pending) {
+ CSP_PRINTF_ERROR("%s: %s: irq:%d pending:0x%x->0x%x\n",
+ NAME_PREFIX, __func__, ipc_evt->ctrl.irq, pending, ipc_hw_read_int_status_reg(AP));
/* don't sleep on ap */
do {
- trycnt++;
- msleep(EVT_WAIT_TIME);
- } while (ipc_hw_read_gen_int_status_reg(AP, ipc_evt->ctrl.irq) && (trycnt < MAX_TRY_CNT));
-
+ busywait(EVT_WAIT_TIME);
+ } while (ipc_hw_read_gen_int_status_reg(AP, ipc_evt->ctrl.irq) && (trycnt++ < MAX_TRY_CNT));
CSP_PRINTF_INFO("%s: %s: pending irq wait: pend:%d irq %d during %d times\n",
NAME_PREFIX, __func__, ipc_hw_read_gen_int_status_reg(AP, ipc_evt->ctrl.irq),
ipc_evt->ctrl.irq, trycnt);
-#endif
+
+ if (ipc_hw_read_gen_int_status_reg(AP, ipc_evt->ctrl.irq)) {
+ CSP_PRINTF_ERROR("%s: %s: fail to add evt by pending:0x%x\n",
+ NAME_PREFIX, __func__, ipc_hw_read_gen_int_status_reg(AP, ipc_evt->ctrl.irq));
+ ENABLE_IRQ();
+ return -1;
+ }
}
cur_evt->evt = evt;
cur_evt->status = IPC_EVT_EQ;
if (ipc_evt->ctrl.eq == __raw_readl(&ipc_evt->ctrl.dq))
__raw_writel(1, &ipc_evt->ctrl.full);
} else {
-#if defined(CHUB_IPC)
+ ENABLE_IRQ();
do {
- trycnt++;
- msleep(EVT_WAIT_TIME);
- } while (ipc_evt->ctrl.full && (trycnt < MAX_TRY_CNT));
+ busywait(EVT_WAIT_TIME);
+ } while (ipc_evt->ctrl.full && (trycnt++ < MAX_TRY_CNT));
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);
- return -1;
+ goto retry;
} else {
- CSP_PRINTF_ERROR("%s: %s: fail to add evt\n", NAME_PREFIX, __func__);
+ CSP_PRINTF_ERROR("%s: %s: fail to add evt by full\n", NAME_PREFIX, __func__);
+ ipc_dump();
return -1;
}
-#else
- CSP_PRINTF_ERROR("%s: %s: fail to add evt\n", NAME_PREFIX, __func__);
- return -1;
-#endif
}
+ ENABLE_IRQ();
if (owner != IPC_OWN_MAX) {
#if defined(AP_IPC)
else
return -1;
}
-
return 0;
}
struct ipc_evt *ipc_evt = &ipc_map->evt[evtq];
int i;
- CSP_PRINTF_INFO("%s: evt-%s: eq:%d dq:%d full:%d irq:%d\n",
- NAME_PREFIX, IPC_GET_EVT_NAME(evtq), ipc_evt->ctrl.eq,
+ CSP_PRINTF_INFO("%s: evt(%p)-%s: eq:%d dq:%d full:%d irq:%d\n",
+ NAME_PREFIX, ipc_evt, IPC_GET_EVT_NAME(evtq), ipc_evt->ctrl.eq,
ipc_evt->ctrl.dq, ipc_evt->ctrl.full,
ipc_evt->ctrl.irq);