From d9bea7f7f40fde27fb2b2a1dd38e51e41f63ae0b Mon Sep 17 00:00:00 2001 From: Amol Jadi Date: Fri, 17 Feb 2023 14:48:02 -0800 Subject: [PATCH] ubwcp: limit error logs Enable read & decode irq only for debug. Rate limit error logs. Change-Id: I782d5af9049bdb501d14f3cbc6a7f868d49da581 Signed-off-by: Amol Jadi --- ubwcp/ubwcp_hw.c | 41 +++--- ubwcp/ubwcp_hw.h | 5 +- ubwcp/ubwcp_main.c | 309 +++++++++++++++++++++++++++++++++------------ 3 files changed, 253 insertions(+), 102 deletions(-) diff --git a/ubwcp/ubwcp_hw.c b/ubwcp/ubwcp_hw.c index ed3e485038..8d32213fb6 100644 --- a/ubwcp/ubwcp_hw.c +++ b/ubwcp/ubwcp_hw.c @@ -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); diff --git a/ubwcp/ubwcp_hw.h b/ubwcp/ubwcp_hw.h index d83191f38f..5fc1f10247 100644 --- a/ubwcp/ubwcp_hw.h +++ b/ubwcp/ubwcp_hw.h @@ -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_ */ diff --git a/ubwcp/ubwcp_main.c b/ubwcp/ubwcp_main.c index 8e3881d89d..4541f70efb 100644 --- a/ubwcp/ubwcp_main.c +++ b/ubwcp/ubwcp_main.c @@ -48,8 +48,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) @@ -57,6 +55,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("") @@ -111,6 +111,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 @@ -194,8 +198,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) { @@ -2119,7 +2122,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); @@ -2404,21 +2406,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, ®_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) @@ -2620,9 +2770,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) { @@ -2636,89 +2783,75 @@ 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; + err.err_code = UBWCP_SMMU_FAULT; - if (cb_dev == ubwcp->dev_desc_cb) - err.smmu_err.iommu_dev_id = UBWCP_DESC_CB_ID; - else if (cb_dev == ubwcp->dev_buf_cb) - 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; - ubwcp_notify_error_handlers(&err); - } + if (cb_dev == ubwcp->dev_desc_cb) + err.smmu_err.iommu_dev_id = UBWCP_DESC_CB_ID; + else if (cb_dev == ubwcp->dev_buf_cb) + err.smmu_err.iommu_dev_id = UBWCP_BUF_CB_ID; + else + err.smmu_err.iommu_dev_id = UBWCP_UNKNOWN_CB_ID; + 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); - 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; - ubwcp_notify_error_handlers(&err); - } + 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); - 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; - ubwcp_notify_error_handlers(&err); - } + 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); - err.err_code = UBWCP_ENCODE_ERROR; - err.enc_err.dmabuf = get_dma_buf_from_ulapa(addr); - err.enc_err.ula_pa = addr; - ubwcp_notify_error_handlers(&err); - } - ubwcp_hw_interrupt_clear(ubwcp->base, 3); //TBD: encode is bit-3 instead of bit-2 + 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); } 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); - err.err_code = UBWCP_DECODE_ERROR; - err.dec_err.dmabuf = get_dma_buf_from_ulapa(addr); - err.dec_err.ula_pa = addr; - ubwcp_notify_error_handlers(&err); - } - ubwcp_hw_interrupt_clear(ubwcp->base, 2); //TBD: decode is bit-2 instead of bit-3 + 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); } else { ERR("unknown irq: %d", irq); return IRQ_NONE; @@ -2849,9 +2982,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)) { @@ -2872,9 +3002,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) { @@ -2910,11 +3048,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 */ - ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_READ_ERROR, true); - ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_WRITE_ERROR, true); - ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_ENCODE_ERROR, true); - ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_DECODE_ERROR, true); + + /* 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); + 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)) {