mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 12:25:00 -04:00
Merge "memory_dump: add new feature for cpuss dump"
This commit is contained in:
commit
18ac4e51b9
1 changed files with 173 additions and 71 deletions
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2014-2017, 2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2014-2017, 2019-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#define INPUT_DATA_BY_HLOS 0x00C0FFEE
|
||||
#define FORMAT_VERSION_1 0x1
|
||||
#define FORMAT_VERSION_2 0x2
|
||||
#define CORE_REG_NUM_DEFAULT 0x1
|
||||
|
||||
#define MAGIC_INDEX 0
|
||||
|
|
@ -36,6 +37,20 @@
|
|||
#define PERCORE_INDEX 4
|
||||
#define SYSTEM_REGS_INPUT_INDEX 5
|
||||
|
||||
#define CMD_REPEAT_READ (0x2 << 24)
|
||||
#define CMD_DELAY (0x1 << 24)
|
||||
#define CMD_READ 0x0
|
||||
#define CMD_READ_WORD 0x1
|
||||
#define CMD_WRITE 0x2
|
||||
#define CMD_EXTRA 0x3
|
||||
|
||||
#define CMD_MASK 0x3
|
||||
#define OFFSET_MASK GENMASK(31, 2)
|
||||
#define EXTRA_CMD_MASK GENMASK(31, 24)
|
||||
#define EXTRA_VALUE_MASK GENMASK(23, 0)
|
||||
#define MAX_EXTRA_VALUE 0xffffff
|
||||
|
||||
|
||||
struct cpuss_dump_data {
|
||||
void *dump_vaddr;
|
||||
u32 size;
|
||||
|
|
@ -105,7 +120,7 @@ static int update_reg_dump_table(struct device *dev, u32 core_reg_num)
|
|||
memset(cpudata->dump_vaddr, 0xDE, cpudata->size);
|
||||
p = (struct reg_dump_data *)cpudata->dump_vaddr;
|
||||
p->magic = INPUT_DATA_BY_HLOS;
|
||||
p->version = FORMAT_VERSION_1;
|
||||
p->version = FORMAT_VERSION_2;
|
||||
p->system_regs_input_index = system_regs_input_index;
|
||||
p->regdump_output_byte_offset = regdump_output_byte_offset;
|
||||
memset((uint32_t *)cpudata->dump_vaddr + PERCORE_INDEX, 0x0,
|
||||
|
|
@ -182,9 +197,8 @@ static ssize_t register_config_show(struct device *dev,
|
|||
char local_buf[64];
|
||||
int len = 0, count = 0;
|
||||
int index, system_index_start, index_end;
|
||||
uint32_t register_offset, length_in_bytes;
|
||||
uint32_t length_in_words;
|
||||
uint32_t *p;
|
||||
uint32_t register_offset, val;
|
||||
uint32_t *p, cmd;
|
||||
struct cpuss_dump_data *cpudata = dev_get_drvdata(dev);
|
||||
|
||||
buf[0] = '\0';
|
||||
|
|
@ -197,7 +211,7 @@ static ssize_t register_config_show(struct device *dev,
|
|||
p = (uint32_t *)cpudata->dump_vaddr;
|
||||
|
||||
/* print per-core & system registers */
|
||||
len = snprintf(local_buf, 64, "per-core registers:\n");
|
||||
len = scnprintf(local_buf, 64, "per-core registers:\n");
|
||||
strlcat(buf, local_buf, PAGE_SIZE);
|
||||
count += len;
|
||||
|
||||
|
|
@ -206,7 +220,7 @@ static ssize_t register_config_show(struct device *dev,
|
|||
cpudata->sys_reg_size / sizeof(uint32_t) + 1;
|
||||
for (index = PERCORE_INDEX; index < index_end;) {
|
||||
if (index == system_index_start) {
|
||||
len = snprintf(local_buf, 64, "system registers:\n");
|
||||
len = scnprintf(local_buf, 64, "system registers:\n");
|
||||
if ((count + len) > PAGE_SIZE) {
|
||||
dev_err(dev, "Couldn't write complete config\n");
|
||||
break;
|
||||
|
|
@ -222,19 +236,44 @@ static ssize_t register_config_show(struct device *dev,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (register_offset & 0x3) {
|
||||
length_in_words = register_offset & 0x3;
|
||||
length_in_bytes = length_in_words << 2;
|
||||
len = snprintf(local_buf, 64,
|
||||
"Index: 0x%x, addr: 0x%x\n",
|
||||
index, register_offset);
|
||||
index++;
|
||||
} else {
|
||||
length_in_bytes = *(p + index + 1);
|
||||
len = snprintf(local_buf, 64,
|
||||
"Index: 0x%x, addr: 0x%x, length: 0x%x\n",
|
||||
index, register_offset, length_in_bytes);
|
||||
cmd = register_offset & CMD_MASK;
|
||||
register_offset &= OFFSET_MASK;
|
||||
|
||||
switch (cmd) {
|
||||
case CMD_READ:
|
||||
val = *(p + index + 1);
|
||||
len = scnprintf(local_buf, 64,
|
||||
"0x%x, 0x%x, r\n",
|
||||
register_offset, val);
|
||||
index += 2;
|
||||
break;
|
||||
case CMD_READ_WORD:
|
||||
len = scnprintf(local_buf, 64,
|
||||
"0x%x, 0x%x, r\n",
|
||||
register_offset, 0x4);
|
||||
index++;
|
||||
break;
|
||||
case CMD_WRITE:
|
||||
val = *(p + index + 1);
|
||||
len = scnprintf(local_buf, 64,
|
||||
"0x%x, 0x%x, w\n",
|
||||
register_offset, val);
|
||||
index += 2;
|
||||
break;
|
||||
case CMD_EXTRA:
|
||||
val = *(p + index + 1);
|
||||
cmd = val & EXTRA_CMD_MASK;
|
||||
val &= EXTRA_VALUE_MASK;
|
||||
if (cmd == CMD_DELAY)
|
||||
len = scnprintf(local_buf, 64,
|
||||
"0x%x, 0x%x, d\n",
|
||||
register_offset, val);
|
||||
else
|
||||
len = scnprintf(local_buf, 64,
|
||||
"0x%x, 0x%x, R\n",
|
||||
register_offset, val);
|
||||
index += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((count + len) > PAGE_SIZE) {
|
||||
|
|
@ -250,6 +289,49 @@ static ssize_t register_config_show(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static int config_cpuss_register(struct device *dev,
|
||||
uint32_t *p, uint32_t index, char cmd,
|
||||
uint32_t register_offset, uint32_t val)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case 'r':
|
||||
if (val > 4) {
|
||||
*(p + index) = register_offset;
|
||||
*(p + index + 1) = val;
|
||||
} else {
|
||||
*(p + index) = register_offset | CMD_READ_WORD;
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
if (val > MAX_EXTRA_VALUE) {
|
||||
dev_err(dev, "repeat read time exceeded the limit\n");
|
||||
ret = -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
*(p + index) = register_offset | CMD_EXTRA;
|
||||
*(p + index + 1) = val | CMD_REPEAT_READ;
|
||||
break;
|
||||
case 'd':
|
||||
if (val > MAX_EXTRA_VALUE) {
|
||||
dev_err(dev, "sleep time exceeded the limit\n");
|
||||
ret = -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
*(p + index) = CMD_EXTRA;
|
||||
*(p + index + 1) = val | CMD_DELAY;
|
||||
break;
|
||||
case 'w':
|
||||
*(p + index) = register_offset | CMD_WRITE;
|
||||
*(p + index + 1) = val;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Don't support this command\n");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* This function sets configs of per-core or system registers.
|
||||
*/
|
||||
|
|
@ -258,9 +340,9 @@ static ssize_t register_config_store(struct device *dev,
|
|||
const char *buf, size_t size)
|
||||
{
|
||||
int ret;
|
||||
uint32_t register_offset, length_in_bytes, per_core = 0;
|
||||
uint32_t length_in_words;
|
||||
uint32_t register_offset, val, reserve_size = 4, per_core = 0;
|
||||
int nval;
|
||||
char cmd;
|
||||
uint32_t num_cores;
|
||||
u32 extra_memory;
|
||||
u32 used_memory;
|
||||
|
|
@ -268,29 +350,37 @@ static ssize_t register_config_store(struct device *dev,
|
|||
uint32_t *p;
|
||||
struct cpuss_dump_data *cpudata = dev_get_drvdata(dev);
|
||||
|
||||
nval = sscanf(buf, "%x %x %u", ®ister_offset,
|
||||
&length_in_bytes, &per_core);
|
||||
if (nval != 2 && nval != 3)
|
||||
nval = sscanf(buf, "%x %x %c %u", ®ister_offset,
|
||||
&val, &cmd, &per_core);
|
||||
if (nval < 2)
|
||||
return -EINVAL;
|
||||
if (nval == 2)
|
||||
cmd = 'r';
|
||||
if (per_core > 1)
|
||||
return -EINVAL;
|
||||
if (register_offset & 0x3) {
|
||||
dev_err(dev, "Invalid address, must be 4 byte aligned\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (length_in_bytes & 0x3) {
|
||||
dev_err(dev, "Invalid length, must be 4 byte aligned\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (length_in_bytes == 0) {
|
||||
dev_err(dev, "Invalid length of 0\n");
|
||||
return -EINVAL;
|
||||
|
||||
if (cmd == 'r' || cmd == 'R') {
|
||||
if (val == 0) {
|
||||
dev_err(dev, "Invalid length of 0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (cmd == 'r' && val & 0x3) {
|
||||
dev_err(dev, "Invalid length, must be 4 byte aligned\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (cmd == 'R')
|
||||
reserve_size = val * 4;
|
||||
else
|
||||
reserve_size = val;
|
||||
}
|
||||
|
||||
mutex_lock(&cpudata->mutex);
|
||||
|
||||
p = (uint32_t *)cpudata->dump_vaddr;
|
||||
length_in_words = length_in_bytes >> 2;
|
||||
if (per_core) { /* per-core register */
|
||||
if (cpudata->core_reg_used_num == cpudata->core_reg_num) {
|
||||
dev_err(dev, "Couldn't add per-core config, out of range\n");
|
||||
|
|
@ -299,26 +389,25 @@ static ssize_t register_config_store(struct device *dev,
|
|||
}
|
||||
|
||||
num_cores = num_possible_cpus();
|
||||
extra_memory = length_in_bytes * num_cores;
|
||||
extra_memory = reserve_size * num_cores;
|
||||
used_memory = cpudata->used_memory + extra_memory;
|
||||
if (extra_memory / num_cores < length_in_bytes ||
|
||||
used_memory > cpudata->size ||
|
||||
used_memory < cpudata->used_memory) {
|
||||
if (extra_memory / num_cores < reserve_size ||
|
||||
used_memory > cpudata->size ||
|
||||
used_memory < cpudata->used_memory) {
|
||||
dev_err(dev, "Couldn't add per-core reg config, no enough memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (length_in_words > 3) {
|
||||
*(p + cpudata->core_reg_end_index) = register_offset;
|
||||
*(p + cpudata->core_reg_end_index + 1) =
|
||||
length_in_bytes;
|
||||
cpudata->core_reg_end_index += 2;
|
||||
} else {
|
||||
*(p + cpudata->core_reg_end_index) = register_offset |
|
||||
length_in_words;
|
||||
ret = config_cpuss_register(dev, p, cpudata->core_reg_end_index,
|
||||
cmd, register_offset, val);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (cmd == 'r' && val == 4)
|
||||
cpudata->core_reg_end_index++;
|
||||
}
|
||||
else
|
||||
cpudata->core_reg_end_index += 2;
|
||||
|
||||
cpudata->core_reg_used_num++;
|
||||
cpudata->used_memory = used_memory;
|
||||
|
|
@ -326,40 +415,34 @@ static ssize_t register_config_store(struct device *dev,
|
|||
system_reg_end_index = *(p + SYS_REG_INPUT_INDEX) +
|
||||
cpudata->sys_reg_size / sizeof(uint32_t);
|
||||
|
||||
if (length_in_words > 3) {
|
||||
extra_memory = sizeof(uint32_t) * 2 + length_in_bytes;
|
||||
used_memory = cpudata->used_memory + extra_memory;
|
||||
if (extra_memory < length_in_bytes ||
|
||||
used_memory > cpudata->size ||
|
||||
used_memory < cpudata->used_memory) {
|
||||
dev_err(dev, "Couldn't add system reg config, no enough memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
if (cmd == 'r' && reserve_size == 4)
|
||||
extra_memory = sizeof(uint32_t) + reserve_size;
|
||||
else
|
||||
extra_memory = sizeof(uint32_t) * 2 + reserve_size;
|
||||
|
||||
*(p + system_reg_end_index) = register_offset;
|
||||
*(p + system_reg_end_index + 1) = length_in_bytes;
|
||||
system_reg_end_index += 2;
|
||||
cpudata->sys_reg_size += sizeof(uint32_t) * 2;
|
||||
} else {
|
||||
extra_memory = sizeof(uint32_t) + length_in_bytes;
|
||||
used_memory = cpudata->used_memory + extra_memory;
|
||||
if (extra_memory < length_in_bytes ||
|
||||
used_memory > cpudata->size ||
|
||||
used_memory < cpudata->used_memory) {
|
||||
dev_err(dev, "Couldn't add system reg config, no enough memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
used_memory = cpudata->used_memory + extra_memory;
|
||||
if (extra_memory < reserve_size ||
|
||||
used_memory > cpudata->size ||
|
||||
used_memory < cpudata->used_memory) {
|
||||
dev_err(dev, "Couldn't add system reg config, no enough memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
*(p + system_reg_end_index) = register_offset |
|
||||
length_in_words;
|
||||
ret = config_cpuss_register(dev, p, system_reg_end_index,
|
||||
cmd, register_offset, val);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (cmd == 'r' && val == 4) {
|
||||
system_reg_end_index++;
|
||||
cpudata->sys_reg_size += sizeof(uint32_t);
|
||||
} else {
|
||||
system_reg_end_index += 2;
|
||||
cpudata->sys_reg_size += sizeof(uint32_t) * 2;
|
||||
}
|
||||
|
||||
cpudata->used_memory = used_memory;
|
||||
|
||||
*(p + system_reg_end_index) = 0x0;
|
||||
*(p + OUTPUT_DUMP_INDEX) = (system_reg_end_index + 1)
|
||||
* sizeof(uint32_t);
|
||||
|
|
@ -373,6 +456,24 @@ err:
|
|||
}
|
||||
static DEVICE_ATTR_RW(register_config);
|
||||
|
||||
static ssize_t format_version_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int ret;
|
||||
struct reg_dump_data *p;
|
||||
struct cpuss_dump_data *cpudata = dev_get_drvdata(dev);
|
||||
|
||||
if (!cpudata)
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&cpudata->mutex);
|
||||
p = (struct reg_dump_data *)cpudata->dump_vaddr;
|
||||
ret = scnprintf(buf, PAGE_SIZE, "%u\n", p->version);
|
||||
|
||||
mutex_unlock(&cpudata->mutex);
|
||||
return ret;
|
||||
}
|
||||
static DEVICE_ATTR_RO(format_version);
|
||||
/**
|
||||
* This function resets the register dump table.
|
||||
*/
|
||||
|
|
@ -397,6 +498,7 @@ static const struct device_attribute *register_dump_attrs[] = {
|
|||
&dev_attr_core_reg_num,
|
||||
&dev_attr_register_config,
|
||||
&dev_attr_register_reset,
|
||||
&dev_attr_format_version,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue