Merge "ubwcp: limit error logs"

This commit is contained in:
qctecmdr
2023-04-11 08:10:25 -07:00
committed by Gerrit - the friendly Code Review server
3 changed files with 253 additions and 102 deletions

View File

@@ -13,18 +13,14 @@
#include "ubwcp_hw.h"
extern u32 ubwcp_debug_trace_enable;
static bool ubwcp_hw_trace_en;
//#define DBG(fmt, args...)
#define DBG(fmt, args...) \
do { \
if (ubwcp_debug_trace_enable) \
if (ubwcp_hw_trace_en) \
pr_err("ubwcp: hw: %s(): " fmt "\n", __func__, ##args); \
} while (0)
#define ERR(fmt, args...) \
do { \
if (ubwcp_debug_trace_enable) \
pr_err("ubwcp: hw: %s(): ~~~ERROR~~~: " fmt "\n", __func__, ##args); \
} while (0)
#define ERR(fmt, args...) pr_err("ubwcp: hw: %s(): ~~~ERROR~~~: " fmt "\n", __func__, ##args);
MODULE_LICENSE("GPL");
@@ -65,6 +61,8 @@ MODULE_LICENSE("GPL");
#define SPARE 0x1188
#define UBWCP_DEBUG_REG_RW
/* read/write register */
#if defined(UBWCP_USE_SMC)
#define UBWCP_REG_READ(_base, _offset) \
@@ -166,20 +164,20 @@ u64 ubwcp_hw_interrupt_src_address(void __iomem *base, u16 interrupt)
switch (interrupt) {
case INTERRUPT_READ_ERROR:
addr_low = UBWCP_REG_READ(base, INTERRUPT_READ_SRC_LOW);
addr_high = UBWCP_REG_READ(base, INTERRUPT_READ_SRC_HIGH) & 0xF;
addr_low = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_READ_SRC_LOW);
addr_high = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_READ_SRC_HIGH) & 0xF;
break;
case INTERRUPT_WRITE_ERROR:
addr_low = UBWCP_REG_READ(base, INTERRUPT_WRITE_SRC_LOW);
addr_high = UBWCP_REG_READ(base, INTERRUPT_WRITE_SRC_HIGH) & 0xF;
addr_low = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_WRITE_SRC_LOW);
addr_high = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_WRITE_SRC_HIGH) & 0xF;
break;
case INTERRUPT_DECODE_ERROR:
addr_low = UBWCP_REG_READ(base, INTERRUPT_DECODE_SRC_LOW);
addr_high = UBWCP_REG_READ(base, INTERRUPT_DECODE_SRC_HIGH) & 0xF;
addr_low = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_DECODE_SRC_LOW);
addr_high = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_DECODE_SRC_HIGH) & 0xF;
break;
case INTERRUPT_ENCODE_ERROR:
addr_low = UBWCP_REG_READ(base, INTERRUPT_ENCODE_SRC_LOW);
addr_high = UBWCP_REG_READ(base, INTERRUPT_ENCODE_SRC_HIGH) & 0xF;
addr_low = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_ENCODE_SRC_LOW);
addr_high = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_ENCODE_SRC_HIGH) & 0xF;
break;
default:
/* TBD: fatal error? */
@@ -356,7 +354,6 @@ void ubwcp_hw_power_vote_status(void __iomem *pwr_ctrl, u8 *vote, u8 *status)
reg = UBWCP_REG_READ(pwr_ctrl, 0);
*vote = (reg & BIT(0)) >> 0;
*status = (reg & BIT(31)) >> 31;
DBG("pwr_ctrl reg: 0x%x (vote = %d status = %d)", reg, *vote, *status);
}
void ubwcp_hw_one_time_init(void __iomem *base)
@@ -383,3 +380,15 @@ void ubwcp_hw_one_time_init(void __iomem *base)
ubwcp_hw_macro_tile_config(base);
}
EXPORT_SYMBOL(ubwcp_hw_one_time_init);
void ubwcp_hw_trace_set(bool value)
{
ubwcp_hw_trace_en = value;
}
EXPORT_SYMBOL(ubwcp_hw_trace_set);
void ubwcp_hw_trace_get(bool *value)
{
*value = ubwcp_hw_trace_en;
}
EXPORT_SYMBOL(ubwcp_hw_trace_get);

View File

@@ -66,8 +66,7 @@ void ubwcp_hw_interrupt_enable(void __iomem *base, u16 interrupt, bool enable);
void ubwcp_hw_power_on(void __iomem *pwr_ctrl, bool power_on);
void ubwcp_hw_one_time_init(void __iomem *base);
int ubwcp_hw_flush(void __iomem *base);
//#define UBWCP_USE_SMC
#define UBWCP_DEBUG_REG_RW
void ubwcp_hw_trace_set(bool value);
void ubwcp_hw_trace_get(bool *value);
#endif /* __UBWCP_HW_H_ */

View File

@@ -49,8 +49,6 @@ MODULE_IMPORT_NS(DMA_BUF);
#define UBWCP_ALIGN(_x, _y) ((((_x) + (_y) - 1)/(_y))*(_y))
//#define DBG(fmt, args...)
//#define DBG_BUF_ATTR(fmt, args...)
#define DBG_BUF_ATTR(fmt, args...) do { if (ubwcp_debug_trace_enable) \
pr_err("ubwcp: %s(): " fmt "\n", __func__, ##args); \
} while (0)
@@ -58,6 +56,8 @@ MODULE_IMPORT_NS(DMA_BUF);
pr_err("ubwcp: %s(): " fmt "\n", __func__, ##args); \
} while (0)
#define ERR(fmt, args...) pr_err("ubwcp: %s(): ~~~ERROR~~~: " fmt "\n", __func__, ##args)
#define ERR_RATE_LIMIT(fmt, args...) pr_err_ratelimited("ubwcp: %s(): ~~~ERROR~~~: " fmt "\n",\
__func__, ##args)
#define FENTRY() DBG("")
@@ -112,6 +112,10 @@ struct ubwcp_driver {
/* debugfs */
struct dentry *debugfs_root;
bool read_err_irq_en;
bool write_err_irq_en;
bool decode_err_irq_en;
bool encode_err_irq_en;
/* ubwcp devices */
struct device *dev; //ubwcp device
@@ -197,8 +201,7 @@ struct ubwcp_buf {
static struct ubwcp_driver *me;
static int error_print_count;
u32 ubwcp_debug_trace_enable;
static u32 ubwcp_debug_trace_enable;
static struct ubwcp_driver *ubwcp_get_driver(void)
{
@@ -2109,7 +2112,6 @@ static int ubwcp_unlock(struct dma_buf *dmabuf, enum dma_data_direction dir)
return -1;
}
error_print_count = 0;
mutex_lock(&buf->lock);
ret = unlock_internal(buf, dir, false);
mutex_unlock(&buf->lock);
@@ -2394,21 +2396,169 @@ static const struct file_operations ubwcp_fops = {
.unlocked_ioctl = ubwcp_ioctl,
};
static int read_err_r_op(void *data, u64 *value)
{
struct ubwcp_driver *ubwcp = data;
*value = ubwcp->read_err_irq_en;
return 0;
}
static int ubwcp_debugfs_init(struct ubwcp_driver *ubwcp)
static int read_err_w_op(void *data, u64 value)
{
struct ubwcp_driver *ubwcp = data;
if (ubwcp_power(ubwcp, true))
return -1;
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_READ_ERROR, value);
ubwcp->read_err_irq_en = value;
if (ubwcp_power(ubwcp, false))
return -1;
return 0;
}
static int write_err_r_op(void *data, u64 *value)
{
struct ubwcp_driver *ubwcp = data;
*value = ubwcp->write_err_irq_en;
return 0;
}
static int write_err_w_op(void *data, u64 value)
{
struct ubwcp_driver *ubwcp = data;
if (ubwcp_power(ubwcp, true))
return -1;
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_WRITE_ERROR, value);
ubwcp->write_err_irq_en = value;
if (ubwcp_power(ubwcp, false))
return -1;
return 0;
}
static int decode_err_r_op(void *data, u64 *value)
{
struct ubwcp_driver *ubwcp = data;
*value = ubwcp->decode_err_irq_en;
return 0;
}
static int decode_err_w_op(void *data, u64 value)
{
struct ubwcp_driver *ubwcp = data;
if (ubwcp_power(ubwcp, true))
return -1;
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_DECODE_ERROR, value);
ubwcp->decode_err_irq_en = value;
if (ubwcp_power(ubwcp, false))
return -1;
return 0;
}
static int encode_err_r_op(void *data, u64 *value)
{
struct ubwcp_driver *ubwcp = data;
*value = ubwcp->encode_err_irq_en;
return 0;
}
static int encode_err_w_op(void *data, u64 value)
{
struct ubwcp_driver *ubwcp = data;
if (ubwcp_power(ubwcp, true))
return -1;
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_ENCODE_ERROR, value);
ubwcp->encode_err_irq_en = value;
if (ubwcp_power(ubwcp, false))
return -1;
return 0;
}
static int reg_rw_trace_w_op(void *data, u64 value)
{
ubwcp_hw_trace_set(value);
return 0;
}
static int reg_rw_trace_r_op(void *data, u64 *value)
{
bool trace_status;
ubwcp_hw_trace_get(&trace_status);
*value = trace_status;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(read_err_fops, read_err_r_op, read_err_w_op, "%d\n");
DEFINE_DEBUGFS_ATTRIBUTE(decode_err_fops, decode_err_r_op, decode_err_w_op, "%d\n");
DEFINE_DEBUGFS_ATTRIBUTE(write_err_fops, write_err_r_op, write_err_w_op, "%d\n");
DEFINE_DEBUGFS_ATTRIBUTE(encode_err_fops, encode_err_r_op, encode_err_w_op, "%d\n");
DEFINE_DEBUGFS_ATTRIBUTE(reg_rw_trace_fops, reg_rw_trace_r_op, reg_rw_trace_w_op, "%d\n");
static void ubwcp_debugfs_init(struct ubwcp_driver *ubwcp)
{
struct dentry *debugfs_root;
struct dentry *dfile;
debugfs_root = debugfs_create_dir("ubwcp", NULL);
if (!debugfs_root) {
pr_warn("Failed to create debugfs for ubwcp\n");
return -1;
if (IS_ERR_OR_NULL(debugfs_root)) {
ERR("Failed to create debugfs for ubwcp\n");
return;
}
debugfs_create_u32("debug_trace_enable", 0644, debugfs_root, &ubwcp_debug_trace_enable);
dfile = debugfs_create_file("reg_rw_trace_en", 0644, debugfs_root, ubwcp, &reg_rw_trace_fops);
if (IS_ERR_OR_NULL(dfile)) {
ERR("failed to create reg_rw_trace_en debugfs file");
goto err;
}
dfile = debugfs_create_file("read_err_irq_en", 0644, debugfs_root, ubwcp, &read_err_fops);
if (IS_ERR_OR_NULL(dfile)) {
ERR("failed to create read_err_irq debugfs file");
goto err;
}
dfile = debugfs_create_file("write_err_irq_en", 0644, debugfs_root, ubwcp, &write_err_fops);
if (IS_ERR_OR_NULL(dfile)) {
ERR("failed to create write_err_irq debugfs file");
goto err;
}
dfile = debugfs_create_file("decode_err_irq_en", 0644, debugfs_root, ubwcp,
&decode_err_fops);
if (IS_ERR_OR_NULL(dfile)) {
ERR("failed to create decode_err_irq debugfs file");
goto err;
}
dfile = debugfs_create_file("encode_err_irq_en", 0644, debugfs_root, ubwcp,
&encode_err_fops);
if (IS_ERR_OR_NULL(dfile)) {
ERR("failed to create encode_err_irq debugfs file");
goto err;
}
ubwcp->debugfs_root = debugfs_root;
return 0;
return;
err:
debugfs_remove_recursive(ubwcp->debugfs_root);
ubwcp->debugfs_root = NULL;
}
static void ubwcp_debugfs_deinit(struct ubwcp_driver *ubwcp)
@@ -2610,9 +2760,6 @@ static struct dma_buf *get_dma_buf_from_iova(unsigned long addr)
return ret_buf;
}
#define ERR_PRINT_COUNT_MAX 21
/* TBD: use proper rate limit for debug prints */
int ubwcp_iommu_fault_handler(struct iommu_domain *domain, struct device *dev,
unsigned long iova, int flags, void *data)
{
@@ -2626,8 +2773,6 @@ int ubwcp_iommu_fault_handler(struct iommu_domain *domain, struct device *dev,
goto err;
}
error_print_count++;
if (error_print_count < ERR_PRINT_COUNT_MAX) {
err.err_code = UBWCP_SMMU_FAULT;
if (cb_dev == ubwcp->dev_desc_cb)
@@ -2636,79 +2781,67 @@ int ubwcp_iommu_fault_handler(struct iommu_domain *domain, struct device *dev,
err.smmu_err.iommu_dev_id = UBWCP_BUF_CB_ID;
else
err.smmu_err.iommu_dev_id = UBWCP_UNKNOWN_CB_ID;
ERR("smmu fault error: iommu_dev_id:%d iova 0x%llx flags:0x%x",
err.smmu_err.iommu_dev_id, iova, flags);
err.smmu_err.dmabuf = get_dma_buf_from_iova(iova);
err.smmu_err.iova = iova;
err.smmu_err.iommu_fault_flags = flags;
ERR_RATE_LIMIT("ubwcp_err: err code: %d (smmu), iommu_dev_id: %d, iova: 0x%llx, flags: 0x%x",
err.err_code, err.smmu_err.iommu_dev_id, err.smmu_err.iova,
err.smmu_err.iommu_fault_flags);
ubwcp_notify_error_handlers(&err);
}
err:
return ret;
}
irqreturn_t ubwcp_irq_handler(int irq, void *ptr)
{
struct ubwcp_driver *ubwcp;
void __iomem *base;
u64 src;
phys_addr_t addr;
struct ubwcp_err_info err;
error_print_count++;
ubwcp = (struct ubwcp_driver *) ptr;
base = ubwcp->base;
if (irq == ubwcp->irq_range_ck_rd) {
if (error_print_count < ERR_PRINT_COUNT_MAX) {
src = ubwcp_hw_interrupt_src_address(base, 0);
addr = src << 6;
ERR("check range read error: src: 0x%llx", addr);
addr = ubwcp_hw_interrupt_src_address(base, 0) << 6;
err.err_code = UBWCP_RANGE_TRANSLATION_ERROR;
err.translation_err.dmabuf = get_dma_buf_from_ulapa(addr);
err.translation_err.ula_pa = addr;
err.translation_err.read = true;
ERR_RATE_LIMIT("ubwcp_err: err code: %d (range), dmabuf: 0x%llx, read: %d, addr: 0x%llx",
err.err_code, err.translation_err.dmabuf, err.translation_err.read, addr);
ubwcp_notify_error_handlers(&err);
}
ubwcp_hw_interrupt_clear(ubwcp->base, 0);
} else if (irq == ubwcp->irq_range_ck_wr) {
if (error_print_count < ERR_PRINT_COUNT_MAX) {
src = ubwcp_hw_interrupt_src_address(base, 1);
addr = src << 6;
ERR("check range write error: src: 0x%llx", addr);
addr = ubwcp_hw_interrupt_src_address(base, 1) << 6;
err.err_code = UBWCP_RANGE_TRANSLATION_ERROR;
err.translation_err.dmabuf = get_dma_buf_from_ulapa(addr);
err.translation_err.ula_pa = addr;
err.translation_err.read = false;
ERR_RATE_LIMIT("ubwcp_err: err code: %d (range), dmabuf: 0x%llx, read: %d, addr: 0x%llx",
err.err_code, err.translation_err.dmabuf, err.translation_err.read, addr);
ubwcp_notify_error_handlers(&err);
}
ubwcp_hw_interrupt_clear(ubwcp->base, 1);
} else if (irq == ubwcp->irq_encode) {
if (error_print_count < ERR_PRINT_COUNT_MAX) {
src = ubwcp_hw_interrupt_src_address(base, 3);
addr = src << 6;
ERR("encode error: src: 0x%llx", addr);
addr = ubwcp_hw_interrupt_src_address(base, 3) << 6;
err.err_code = UBWCP_ENCODE_ERROR;
err.enc_err.dmabuf = get_dma_buf_from_ulapa(addr);
err.enc_err.ula_pa = addr;
ERR_RATE_LIMIT("ubwcp_err: err code: %d (encode), dmabuf: 0x%llx, addr: 0x%llx",
err.err_code, err.enc_err.dmabuf, addr);
ubwcp_notify_error_handlers(&err);
}
ubwcp_hw_interrupt_clear(ubwcp->base, 3); //TBD: encode is bit-3 instead of bit-2
ubwcp_hw_interrupt_clear(ubwcp->base, 3);
} else if (irq == ubwcp->irq_decode) {
if (error_print_count < ERR_PRINT_COUNT_MAX) {
src = ubwcp_hw_interrupt_src_address(base, 2);
addr = src << 6;
ERR("decode error: src: 0x%llx", addr);
addr = ubwcp_hw_interrupt_src_address(base, 2) << 6;
err.err_code = UBWCP_DECODE_ERROR;
err.dec_err.dmabuf = get_dma_buf_from_ulapa(addr);
err.dec_err.ula_pa = addr;
ERR_RATE_LIMIT("ubwcp_err: err code: %d (decode), dmabuf: 0x%llx, addr: 0x%llx",
err.err_code, err.enc_err.dmabuf, addr);
ubwcp_notify_error_handlers(&err);
}
ubwcp_hw_interrupt_clear(ubwcp->base, 2); //TBD: decode is bit-2 instead of bit-3
ubwcp_hw_interrupt_clear(ubwcp->base, 2);
} else {
ERR("unknown irq: %d", irq);
return IRQ_NONE;
@@ -2839,9 +2972,6 @@ static int qcom_ubwcp_probe(struct platform_device *pdev)
mutex_init(&ubwcp->hw_range_ck_lock);
spin_lock_init(&ubwcp->err_handler_list_lock);
if (ubwcp_interrupt_register(pdev, ubwcp))
return -1;
/* Regulator */
ubwcp->vdd = devm_regulator_get(ubwcp_dev, "vdd");
if (IS_ERR_OR_NULL(ubwcp->vdd)) {
@@ -2862,9 +2992,17 @@ static int qcom_ubwcp_probe(struct platform_device *pdev)
if (ubwcp_cdev_init(ubwcp))
return -1;
if (ubwcp_debugfs_init(ubwcp))
/* disable all interrupts (reset value has some interrupts enabled by default) */
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_READ_ERROR, false);
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_WRITE_ERROR, false);
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_ENCODE_ERROR, false);
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_DECODE_ERROR, false);
if (ubwcp_interrupt_register(pdev, ubwcp))
return -1;
ubwcp_debugfs_init(ubwcp);
/* create ULA pool */
ubwcp->ula_pool = gen_pool_create(12, -1);
if (!ubwcp->ula_pool) {
@@ -2900,11 +3038,16 @@ static int qcom_ubwcp_probe(struct platform_device *pdev)
/* set pdev->dev->driver_data = ubwcp */
platform_set_drvdata(pdev, ubwcp);
/* enable all 4 interrupts */
/* enable interrupts */
if (ubwcp->read_err_irq_en)
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_READ_ERROR, true);
if (ubwcp->write_err_irq_en)
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_WRITE_ERROR, true);
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_ENCODE_ERROR, true);
if (ubwcp->decode_err_irq_en)
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_DECODE_ERROR, true);
if (ubwcp->encode_err_irq_en)
ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_ENCODE_ERROR, true);
/* Turn OFF until buffers are allocated */
if (ubwcp_power(ubwcp, false)) {