608 lines
16 KiB
C
608 lines
16 KiB
C
|
/*
|
||
|
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*/
|
||
|
|
||
|
#include <linux/io.h>
|
||
|
#include <linux/debugfs.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/iommu.h>
|
||
|
#include <linux/of_reserved_mem.h>
|
||
|
#include <linux/uaccess.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include "chub_dbg.h"
|
||
|
#include "chub_ipc.h"
|
||
|
#include "chub.h"
|
||
|
#ifdef CONFIG_CHRE_SENSORHUB_HAL
|
||
|
#include "main.h"
|
||
|
#endif
|
||
|
#ifdef CONFIG_SENSORS_SSP
|
||
|
#include "../../sensorhub/ssp_platform.h"
|
||
|
#define SUPPORT_DUMP_ON_DRIVER
|
||
|
#endif
|
||
|
|
||
|
#define NUM_OF_GPR (17)
|
||
|
#define GPR_PC_INDEX (16)
|
||
|
#define AREA_NAME_MAX (8)
|
||
|
/* it's align ramdump side to prevent override */
|
||
|
#define SRAM_ALIGN (1024)
|
||
|
#define S_IRWUG (0660)
|
||
|
|
||
|
struct map_info {
|
||
|
char name[AREA_NAME_MAX];
|
||
|
u32 offset;
|
||
|
u32 size;
|
||
|
};
|
||
|
|
||
|
struct dbg_dump {
|
||
|
struct map_info info[DBG_AREA_MAX];
|
||
|
long long time;
|
||
|
int reason;
|
||
|
struct contexthub_ipc_info chub;
|
||
|
struct ipc_area ipc_addr[IPC_REG_MAX];
|
||
|
u32 gpr[NUM_OF_GPR];
|
||
|
int sram_start;
|
||
|
char sram[];
|
||
|
};
|
||
|
|
||
|
static struct dbg_dump *p_dbg_dump;
|
||
|
static struct reserved_mem *chub_rmem;
|
||
|
|
||
|
static void chub_dbg_dump_gpr(struct contexthub_ipc_info *ipc)
|
||
|
{
|
||
|
if (p_dbg_dump) {
|
||
|
int i;
|
||
|
struct dbg_dump *p_dump = p_dbg_dump;
|
||
|
|
||
|
IPC_HW_WRITE_DUMPGPR_CTRL(ipc->chub_dumpgpr, 0x1);
|
||
|
/* dump GPR */
|
||
|
for (i = 0; i <= GPR_PC_INDEX - 1; i++)
|
||
|
p_dump->gpr[i] =
|
||
|
readl(ipc->chub_dumpgpr + REG_CHUB_DUMPGPR_GP0R +
|
||
|
i * 4);
|
||
|
p_dump->gpr[GPR_PC_INDEX] =
|
||
|
readl(ipc->chub_dumpgpr + REG_CHUB_DUMPGPR_PCR);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static u32 get_dbg_dump_size(void)
|
||
|
{
|
||
|
return sizeof(struct dbg_dump) + ipc_get_chub_mem_size();
|
||
|
};
|
||
|
|
||
|
#if defined(CONFIG_CONTEXTHUB_DEBUG) && defined(SUPPORT_DUMP_ON_DRIVER)
|
||
|
static void chub_dbg_write_file(struct device *dev, char *name, void *buf, int size)
|
||
|
{
|
||
|
struct file *filp;
|
||
|
char file_name[64];
|
||
|
mm_segment_t old_fs;
|
||
|
struct dbg_dump *p_dump = p_dbg_dump;
|
||
|
u32 sec = p_dump->time / NSEC_PER_SEC;
|
||
|
|
||
|
snprintf(file_name, sizeof(file_name), "%s/nano-%02u-%06u-%s.dump",
|
||
|
CHUB_DBG_DIR, p_dump->reason, sec, name);
|
||
|
|
||
|
old_fs = get_fs();
|
||
|
set_fs(get_ds());
|
||
|
|
||
|
filp = filp_open(file_name, O_RDWR|O_CREAT|O_APPEND, 0666);
|
||
|
if (IS_ERR(filp)) {
|
||
|
dev_warn(dev, "%s: open '%s' file fail\n",
|
||
|
__func__, file_name);
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
vfs_write(filp, buf, size, &filp->f_pos);
|
||
|
vfs_fsync(filp, 0);
|
||
|
filp_close(filp, NULL);
|
||
|
|
||
|
dev_dbg(dev, "%s is created with %d size\n", file_name,
|
||
|
get_dbg_dump_size());
|
||
|
out:
|
||
|
set_fs(old_fs);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* dump hw into dram (chub reserved mem) */
|
||
|
static void chub_dbg_dump_ram(struct contexthub_ipc_info *ipc, enum chub_err_type reason)
|
||
|
{
|
||
|
if (p_dbg_dump) {
|
||
|
p_dbg_dump->time = sched_clock();
|
||
|
p_dbg_dump->reason = reason;
|
||
|
|
||
|
ipc_dump();
|
||
|
/* dump SRAM to reserved DRAM */
|
||
|
memcpy_fromio(&p_dbg_dump->sram[p_dbg_dump->sram_start],
|
||
|
ipc_get_base(IPC_REG_DUMP),
|
||
|
ipc_get_chub_mem_size());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void chub_dbg_dump_status(struct contexthub_ipc_info *ipc)
|
||
|
{
|
||
|
int i;
|
||
|
char *dbg_name[CHUB_ERR_MAX] = {"none", "evtq_empty",
|
||
|
"read_fail", "write_fail", "evtq_no_hw_trigger",
|
||
|
"chub_no_resp", "itmon", "fw_fault", "fw_wdt",
|
||
|
"fw_err", "comms_nack", "comms_busy",
|
||
|
"comms_unknown", "comms", "reset_cnt", "fw_dbg"};
|
||
|
|
||
|
#ifdef CONFIG_CHRE_SENSORHUB_HAL
|
||
|
struct nanohub_data *data = ipc->data;
|
||
|
|
||
|
dev_info(ipc->dev,
|
||
|
"%s: nanohub driver status\nwu:%d wu_l:%d acq:%d irq1_apInt:%d fired:%d\n",
|
||
|
__func__,
|
||
|
atomic_read(&data->wakeup_cnt),
|
||
|
atomic_read(&data->wakeup_lock_cnt),
|
||
|
atomic_read(&data->wakeup_acquired),
|
||
|
atomic_read(&ipc->irq1_apInt), nanohub_irq1_fired(data));
|
||
|
#endif
|
||
|
|
||
|
/* print error status */
|
||
|
for (i = 0; i < CHUB_ERR_MAX; i++) {
|
||
|
if (ipc->err_cnt[i])
|
||
|
dev_info(ipc->dev, "%s: err(%d:%s) %d times\n",
|
||
|
__func__, i, dbg_name[i], ipc->err_cnt[i]);
|
||
|
}
|
||
|
|
||
|
#ifdef USE_FW_DUMP
|
||
|
contexthub_ipc_write_event(ipc, MAILBOX_EVT_DUMP_STATUS);
|
||
|
#endif
|
||
|
log_flush(ipc->fw_log);
|
||
|
}
|
||
|
|
||
|
|
||
|
void chub_dbg_dump_hw(struct contexthub_ipc_info *ipc, enum chub_err_type reason)
|
||
|
{
|
||
|
dev_info(ipc->dev, "%s: reason:%d\n", __func__, reason);
|
||
|
|
||
|
chub_dbg_dump_gpr(ipc);
|
||
|
chub_dbg_dump_ram(ipc, reason);
|
||
|
|
||
|
#ifdef CONFIG_CHRE_SENSORHUB_HAL
|
||
|
nanohub_add_dump_request(ipc->data);
|
||
|
#endif
|
||
|
#ifdef CONFIG_SENSORS_SSP
|
||
|
ssp_dump_write_file(ipc->ssp_data, &p_dbg_dump->sram[p_dbg_dump->sram_start], ipc_get_chub_mem_size(), reason);
|
||
|
#endif
|
||
|
|
||
|
#ifdef SUPPORT_DUMP_ON_DRIVER
|
||
|
/* dosen't support on android-p */
|
||
|
if (p_dbg_dump) {
|
||
|
#ifdef CONFIG_CONTEXTHUB_DEBUG
|
||
|
/* write file */
|
||
|
dev_info(ipc->dev,
|
||
|
"%s: write file: size:%d\n",
|
||
|
__func__, ipc_get_chub_mem_size());
|
||
|
|
||
|
chub_dbg_write_file(ipc->dev, "dram",
|
||
|
p_dbg_dump, sizeof(struct dbg_dump));
|
||
|
|
||
|
chub_dbg_write_file(ipc->dev, "sram",
|
||
|
&p_dbg_dump->sram[p_dbg_dump->sram_start],
|
||
|
ipc_get_chub_mem_size());
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/* dump log and status with ipc */
|
||
|
chub_dbg_dump_status(ipc);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int chub_dbg_check_and_download_image(struct contexthub_ipc_info *ipc)
|
||
|
{
|
||
|
u32 *bl = vmalloc(ipc_get_offset(IPC_REG_BL));
|
||
|
int ret = 0;
|
||
|
|
||
|
memcpy_fromio(bl, ipc_get_base(IPC_REG_BL), ipc_get_offset(IPC_REG_BL));
|
||
|
contexthub_download_image(ipc, IPC_REG_BL);
|
||
|
|
||
|
ret = memcmp(bl, ipc_get_base(IPC_REG_BL), ipc_get_offset(IPC_REG_BL));
|
||
|
if (ret) {
|
||
|
int i;
|
||
|
u32 *bl_image = (u32 *)ipc_get_base(IPC_REG_BL);
|
||
|
|
||
|
pr_info("bl doens't match with size %d\n", ipc_get_offset(IPC_REG_BL));
|
||
|
|
||
|
for (i = 0; i < ipc_get_offset(IPC_REG_BL) / 4; i++)
|
||
|
if (bl[i] != bl_image[i]) {
|
||
|
pr_info("bl[%d] %x -> wrong %x\n", i,
|
||
|
bl_image[i], bl[i]);
|
||
|
ret = -EINVAL;
|
||
|
goto out;
|
||
|
}
|
||
|
}
|
||
|
contexthub_download_image(ipc, IPC_REG_OS);
|
||
|
|
||
|
/* os image is dumped on &p_dbg_dump->sram[p_dbg_dump->sram_start] */
|
||
|
ret = memcmp(&p_dbg_dump->sram[p_dbg_dump->sram_start],
|
||
|
ipc_get_base(IPC_REG_OS), ipc_get_offset(IPC_REG_OS));
|
||
|
|
||
|
if (ret) {
|
||
|
pr_info("os doens't match with size %d\n",
|
||
|
ipc_get_offset(IPC_REG_OS));
|
||
|
ret = -EINVAL;
|
||
|
}
|
||
|
|
||
|
out:
|
||
|
vfree(bl);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
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(%lld, %zu)\n", __func__, off, size);
|
||
|
memcpy_fromio(buf, battr->private + off, size);
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
static ssize_t chub_bin_dram_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(%lld, %zu)\n", __func__, off, size);
|
||
|
memcpy(buf, battr->private + off, size);
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
static ssize_t chub_bin_dumped_sram_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 struct bin_attribute *chub_bin_attrs[] = {
|
||
|
&bin_attr_chub_bin_sram,
|
||
|
&bin_attr_chub_bin_dram,
|
||
|
&bin_attr_chub_bin_dumped_sram,
|
||
|
};
|
||
|
|
||
|
#define SIZE_UTC_NAME (16)
|
||
|
|
||
|
char chub_utc_name[][SIZE_UTC_NAME] = {
|
||
|
[IPC_DEBUG_UTC_STOP] = "stop",
|
||
|
[IPC_DEBUG_UTC_AGING] = "aging",
|
||
|
[IPC_DEBUG_UTC_WDT] = "wdt",
|
||
|
[IPC_DEBUG_UTC_RTC] = "rtc",
|
||
|
[IPC_DEBUG_UTC_TIMER] = "timer",
|
||
|
[IPC_DEBUG_UTC_MEM] = "mem",
|
||
|
[IPC_DEBUG_UTC_GPIO] = "gpio",
|
||
|
[IPC_DEBUG_UTC_SPI] = "spi",
|
||
|
[IPC_DEBUG_UTC_CMU] = "cmu",
|
||
|
[IPC_DEBUG_UTC_GPIO] = "gpio",
|
||
|
[IPC_DEBUG_UTC_TIME_SYNC] = "time_sync",
|
||
|
[IPC_DEBUG_UTC_ASSERT] = "assert",
|
||
|
[IPC_DEBUG_UTC_FAULT] = "fault",
|
||
|
[IPC_DEBUG_UTC_CHECK_STATUS] = "stack",
|
||
|
[IPC_DEBUG_UTC_CHECK_CPU_UTIL] = "utilization",
|
||
|
[IPC_DEBUG_UTC_HEAP_DEBUG] = "heap",
|
||
|
[IPC_DEBUG_UTC_HANG] = "hang",
|
||
|
[IPC_DEBUG_UTC_HANG_ITMON] = "itmon",
|
||
|
};
|
||
|
|
||
|
static ssize_t chub_alive_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
int index = 0;
|
||
|
struct contexthub_ipc_info *ipc = dev_get_drvdata(dev);
|
||
|
int ret = contexthub_ipc_write_event(ipc, MAILBOX_EVT_CHUB_ALIVE);
|
||
|
|
||
|
if (!ret)
|
||
|
index += sprintf(buf, "chub alive\n");
|
||
|
else
|
||
|
index += sprintf(buf, "chub isn't alive\n");
|
||
|
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
static ssize_t chub_utc_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
int i;
|
||
|
int index = 0;
|
||
|
|
||
|
for (i = 0; i < sizeof(chub_utc_name) / SIZE_UTC_NAME; i++)
|
||
|
if (chub_utc_name[i][0])
|
||
|
index +=
|
||
|
sprintf(buf + index, "%d %s\n", i,
|
||
|
chub_utc_name[i]);
|
||
|
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
static ssize_t chub_utc_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 err;
|
||
|
|
||
|
err = kstrtol(&buf[0], 10, &event);
|
||
|
dev_info(ipc->dev, "%s: event:%d\n", __func__, event);
|
||
|
|
||
|
if (!err) {
|
||
|
contexthub_ipc_write_event(ipc, event);
|
||
|
return count;
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static ssize_t chub_ipc_store(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
const char *buf, size_t count)
|
||
|
{
|
||
|
struct contexthub_ipc_info *ipc = dev_get_drvdata(dev);
|
||
|
char input[PACKET_SIZE_MAX];
|
||
|
char output[PACKET_SIZE_MAX];
|
||
|
int ret;
|
||
|
|
||
|
memset(input, 0, PACKET_SIZE_MAX);
|
||
|
memset(output, 0, PACKET_SIZE_MAX);
|
||
|
|
||
|
if (count <= PACKET_SIZE_MAX) {
|
||
|
memset(input, 0, PACKET_SIZE_MAX);
|
||
|
memcpy(input, buf, count);
|
||
|
} else {
|
||
|
dev_err(ipc->dev, "%s: ipc size(%d) is bigger than max(%d)\n",
|
||
|
__func__, (int)count, (int)PACKET_SIZE_MAX);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
ret = contexthub_ipc_write_event(ipc, (u32)IPC_DEBUG_UTC_IPC_TEST_START);
|
||
|
if (ret) {
|
||
|
dev_err(ipc->dev, "%s: fails to set start test event. ret:%d\n", __func__, ret);
|
||
|
count = ret;
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
ret = contexthub_ipc_write(ipc, input, count, IPC_MAX_TIMEOUT);
|
||
|
if (ret != count) {
|
||
|
dev_info(ipc->dev, "%s: fail to write\n", __func__);
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
ret = contexthub_ipc_read(ipc, output, 0, IPC_MAX_TIMEOUT);
|
||
|
if (count != ret) {
|
||
|
dev_info(ipc->dev, "%s: fail to read ret:%d\n", __func__, ret);
|
||
|
}
|
||
|
|
||
|
if (strncmp(input, output, count)) {
|
||
|
dev_info(ipc->dev, "%s: fail to compare input/output\n", __func__);
|
||
|
print_hex_dump(KERN_CONT, "chub input:",
|
||
|
DUMP_PREFIX_OFFSET, 16, 1, input,
|
||
|
count, false);
|
||
|
print_hex_dump(KERN_CONT, "chub output:",
|
||
|
DUMP_PREFIX_OFFSET, 16, 1, output,
|
||
|
count, false);
|
||
|
} else
|
||
|
dev_info(ipc->dev, "[%s pass] len:%d, str: %s\n", __func__, (int)count, output);
|
||
|
|
||
|
out:
|
||
|
ret = contexthub_ipc_write_event(ipc, (u32)IPC_DEBUG_UTC_IPC_TEST_END);
|
||
|
if (ret) {
|
||
|
dev_err(ipc->dev, "%s: fails to set end test event. ret:%d\n", __func__, ret);
|
||
|
count = ret;
|
||
|
}
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static ssize_t chub_get_dump_status_store(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
const char *buf, size_t count)
|
||
|
{
|
||
|
struct contexthub_ipc_info *ipc = dev_get_drvdata(dev);
|
||
|
|
||
|
chub_dbg_dump_status(ipc);
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static ssize_t chub_get_gpr_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
struct contexthub_ipc_info *ipc = dev_get_drvdata(dev);
|
||
|
char *pbuf = buf;
|
||
|
int i;
|
||
|
|
||
|
if (p_dbg_dump) {
|
||
|
chub_dbg_dump_gpr(ipc);
|
||
|
|
||
|
pbuf +=
|
||
|
sprintf(pbuf, "========================================\n");
|
||
|
pbuf += sprintf(pbuf, "CHUB CPU register dump\n");
|
||
|
|
||
|
for (i = 0; i <= 15; i++)
|
||
|
pbuf +=
|
||
|
sprintf(pbuf, "R%02d : %08x\n", i,
|
||
|
p_dbg_dump->gpr[i]);
|
||
|
|
||
|
pbuf +=
|
||
|
sprintf(pbuf, "PC : %08x\n",
|
||
|
p_dbg_dump->gpr[GPR_PC_INDEX]);
|
||
|
pbuf +=
|
||
|
sprintf(pbuf, "========================================\n");
|
||
|
}
|
||
|
|
||
|
return pbuf - buf;
|
||
|
}
|
||
|
|
||
|
static ssize_t chub_set_dump_hw_store(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
const char *buf, size_t count)
|
||
|
{
|
||
|
struct contexthub_ipc_info *ipc = dev_get_drvdata(dev);
|
||
|
|
||
|
chub_dbg_dump_hw(ipc, 0);
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static ssize_t chub_wakeup_store(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
const char *buf, size_t count)
|
||
|
{
|
||
|
long event;
|
||
|
int ret;
|
||
|
struct contexthub_ipc_info *ipc = dev_get_drvdata(dev);
|
||
|
|
||
|
ret = kstrtol(&buf[0], 10, &event);
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
|
||
|
if (event)
|
||
|
ret = contexthub_request(ipc);
|
||
|
else
|
||
|
contexthub_release(ipc);
|
||
|
|
||
|
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(dump_hw, 0220, NULL, chub_set_dump_hw_store),
|
||
|
__ATTR(utc, 0664, chub_utc_show, chub_utc_store),
|
||
|
__ATTR(ipc_test, 0220, NULL, chub_ipc_store),
|
||
|
__ATTR(alive, 0440, chub_alive_show, NULL),
|
||
|
__ATTR(wakeup, 0220, NULL, chub_wakeup_store),
|
||
|
};
|
||
|
|
||
|
void *chub_dbg_get_memory(enum dbg_dump_area area)
|
||
|
{
|
||
|
void *addr;
|
||
|
int size;
|
||
|
|
||
|
pr_info("%s: chub_rmem\n", __func__);
|
||
|
|
||
|
if (!chub_rmem)
|
||
|
return NULL;
|
||
|
|
||
|
if (area == DBG_NANOHUB_DD_AREA) {
|
||
|
addr = &p_dbg_dump->chub;
|
||
|
size = sizeof(p_dbg_dump->chub);
|
||
|
} else {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
memset(addr, 0, size);
|
||
|
|
||
|
return addr;
|
||
|
}
|
||
|
|
||
|
int chub_dbg_init(struct contexthub_ipc_info *chub)
|
||
|
{
|
||
|
int i, ret = 0;
|
||
|
enum dbg_dump_area area;
|
||
|
|
||
|
struct device *dev;
|
||
|
struct device *sensor_dev = NULL;
|
||
|
|
||
|
if (!chub_rmem || !chub)
|
||
|
return -EINVAL;
|
||
|
|
||
|
sensor_dev = dev = chub->dev;
|
||
|
#ifdef CONFIG_CHRE_SENSORHUB_HAL
|
||
|
if (chub->data)
|
||
|
sensor_dev = chub->data->io[ID_NANOHUB_SENSOR].dev;
|
||
|
#endif
|
||
|
|
||
|
pr_info("%s: %s: %s\n", __func__, dev_name(dev), dev_name(sensor_dev));
|
||
|
|
||
|
bin_attr_chub_bin_dumped_sram.size = ipc_get_chub_mem_size();
|
||
|
bin_attr_chub_bin_dumped_sram.private = p_dbg_dump->sram;
|
||
|
|
||
|
bin_attr_chub_bin_dram.size = sizeof(struct dbg_dump);
|
||
|
bin_attr_chub_bin_dram.private= p_dbg_dump;
|
||
|
|
||
|
bin_attr_chub_bin_sram.size = ipc_get_chub_mem_size();
|
||
|
bin_attr_chub_bin_sram.private = ipc_get_base(IPC_REG_DUMP);
|
||
|
|
||
|
if (chub_rmem->size < get_dbg_dump_size())
|
||
|
dev_err(dev,
|
||
|
"rmem size (%u) should be bigger than dump size(%u)\n",
|
||
|
(u32)chub_rmem->size, get_dbg_dump_size());
|
||
|
|
||
|
for (i = 0; i < ARRAY_SIZE(chub_bin_attrs); i++) {
|
||
|
struct bin_attribute *battr = chub_bin_attrs[i];
|
||
|
|
||
|
ret = device_create_bin_file(sensor_dev, battr);
|
||
|
if (ret < 0)
|
||
|
dev_warn(sensor_dev, "Failed to create file: %s\n",
|
||
|
battr->attr.name);
|
||
|
}
|
||
|
|
||
|
for (i = 0, ret = 0; i < ARRAY_SIZE(attributes); i++) {
|
||
|
ret = device_create_file(dev, &attributes[i]);
|
||
|
if (ret)
|
||
|
dev_warn(dev, "Failed to create file: %s\n",
|
||
|
attributes[i].attr.name);
|
||
|
}
|
||
|
|
||
|
area = DBG_IPC_AREA;
|
||
|
strncpy(p_dbg_dump->info[area].name, "ipc_map", AREA_NAME_MAX);
|
||
|
p_dbg_dump->info[area].offset =
|
||
|
(void *)p_dbg_dump->ipc_addr - (void *)p_dbg_dump;
|
||
|
p_dbg_dump->info[area].size = sizeof(struct ipc_area) * IPC_REG_MAX;
|
||
|
|
||
|
area = DBG_NANOHUB_DD_AREA;
|
||
|
strncpy(p_dbg_dump->info[area].name, "nano_dd", AREA_NAME_MAX);
|
||
|
p_dbg_dump->info[area].offset =
|
||
|
(void *)&p_dbg_dump->chub - (void *)p_dbg_dump;
|
||
|
p_dbg_dump->info[area].size = sizeof(struct contexthub_ipc_info);
|
||
|
|
||
|
area = DBG_GPR_AREA;
|
||
|
strncpy(p_dbg_dump->info[area].name, "gpr", AREA_NAME_MAX);
|
||
|
p_dbg_dump->info[area].offset =
|
||
|
(void *)p_dbg_dump->gpr - (void *)p_dbg_dump;
|
||
|
p_dbg_dump->info[area].size = sizeof(u32) * NUM_OF_GPR;
|
||
|
|
||
|
area = DBG_SRAM_AREA;
|
||
|
/* align the chub sram dump base address on rmem into SRAM_ALIN */
|
||
|
p_dbg_dump->sram_start = SRAM_ALIGN - bin_attr_chub_bin_dram.size;
|
||
|
if (p_dbg_dump->sram_start < 0) {
|
||
|
dev_warn(dev,
|
||
|
"increase SRAM_ALIGN from %d to %d to align on ramdump.\n",
|
||
|
SRAM_ALIGN, (u32)bin_attr_chub_bin_dram.size);
|
||
|
p_dbg_dump->sram_start = 0;
|
||
|
}
|
||
|
strncpy(p_dbg_dump->info[area].name, "sram", AREA_NAME_MAX);
|
||
|
p_dbg_dump->info[area].offset =
|
||
|
(void *)&p_dbg_dump->sram[p_dbg_dump->sram_start] -
|
||
|
(void *)p_dbg_dump;
|
||
|
p_dbg_dump->info[area].size = bin_attr_chub_bin_sram.size;
|
||
|
|
||
|
dev_info(dev,
|
||
|
"%s is mapped (startoffset:%d) with size of %u, dump size %u\n",
|
||
|
"dump buffer", p_dbg_dump->sram_start, (u32)chub_rmem->size, get_dbg_dump_size());
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int __init contexthub_rmem_setup(struct reserved_mem *rmem)
|
||
|
{
|
||
|
pr_info("%s", __func__);
|
||
|
|
||
|
chub_rmem = rmem;
|
||
|
p_dbg_dump = phys_to_virt(rmem->base);
|
||
|
return 0;
|
||
|
}
|
||
|
RESERVEDMEM_OF_DECLARE(chub_rmem, "exynos,chub_rmem", contexthub_rmem_setup);
|