Loading drivers/gpu/drm/msm/sde_dbg.c +473 −12 Original line number Diff line number Diff line Loading @@ -67,6 +67,11 @@ #define DBG_CTRL_RESET_HW_PANIC BIT(2) #define DBG_CTRL_MAX BIT(3) #define DUMP_BUF_SIZE (4096 * 512) #define DUMP_CLMN_COUNT 4 #define DUMP_LINE_SIZE 256 #define DUMP_MAX_LINES_PER_BLK 512 /** * struct sde_dbg_reg_offset - tracking for start and end of region * @start: start offset Loading Loading @@ -162,6 +167,29 @@ struct sde_dbg_vbif_debug_bus { struct vbif_debug_bus_entry *entries; }; struct sde_dbg_dsi_debug_bus { u32 *entries; u32 size; }; /** * struct sde_dbg_regbuf - wraps buffer and tracking params for register dumps * @buf: pointer to allocated memory for storing register dumps in hw recovery * @buf_size: size of the memory allocated * @len: size of the dump data valid in the buffer * @rpos: cursor points to the buffer position read by client * @dump_done: to indicate if dumping to user memory is complete * @cur_blk: points to the current sde_dbg_reg_base block */ struct sde_dbg_regbuf { char *buf; int buf_size; int len; int rpos; int dump_done; struct sde_dbg_reg_base *cur_blk; }; /** * struct sde_dbg_base - global sde debug base structure * @evtlog: event log instance Loading @@ -178,6 +206,10 @@ struct sde_dbg_vbif_debug_bus { * @dbgbus_vbif_rt: debug bus structure for the realtime vbif * @dump_all: dump all entries in register dump * @dsi_dbg_bus: dump dsi debug bus register * @regbuf: buffer data to track the register dumping in hw recovery * @cur_evt_index: index used for tracking event logs dump in hw recovery * @dbgbus_dump_idx: index used for tracking dbg-bus dump in hw recovery * @vbif_dbgbus_dump_idx: index for tracking vbif dumps in hw recovery */ static struct sde_dbg_base { struct sde_dbg_evtlog *evtlog; Loading @@ -195,9 +227,15 @@ static struct sde_dbg_base { struct sde_dbg_sde_debug_bus dbgbus_sde; struct sde_dbg_vbif_debug_bus dbgbus_vbif_rt; struct sde_dbg_dsi_debug_bus dbgbus_dsi; bool dump_all; bool dsi_dbg_bus; u32 debugfs_ctrl; struct sde_dbg_regbuf regbuf; u32 cur_evt_index; u32 dbgbus_dump_idx; u32 vbif_dbgbus_dump_idx; } sde_dbg_base; /* sde_dbg_base_evtlog - global pointer to main sde event log for macro use */ Loading Loading @@ -3292,6 +3330,42 @@ static struct vbif_debug_bus_entry vbif_dbg_bus_msm8998[] = { {0x21c, 0x214, 0, 14, 0, 0xc}, /* xin blocks - clock side */ }; static u32 dsi_dbg_bus_sdm845[] = { 0x0001, 0x1001, 0x0001, 0x0011, 0x1021, 0x0021, 0x0031, 0x0041, 0x0051, 0x0061, 0x3061, 0x0061, 0x2061, 0x2061, 0x1061, 0x1061, 0x1061, 0x0071, 0x0071, 0x0071, 0x0081, 0x0081, 0x00A1, 0x00A1, 0x10A1, 0x20A1, 0x30A1, 0x10A1, 0x10A1, 0x30A1, 0x20A1, 0x00B1, 0x00C1, 0x00C1, 0x10C1, 0x20C1, 0x30C1, 0x00D1, 0x00D1, 0x20D1, 0x30D1, 0x00E1, 0x00E1, 0x00E1, 0x00F1, 0x00F1, 0x0101, 0x0101, 0x1101, 0x2101, 0x3101, 0x0111, 0x0141, 0x1141, 0x0141, 0x1141, 0x1141, 0x0151, 0x0151, 0x1151, 0x2151, 0x3151, 0x0161, 0x0161, 0x1161, 0x0171, 0x0171, 0x0181, 0x0181, 0x0191, 0x0191, 0x01A1, 0x01A1, 0x01B1, 0x01B1, 0x11B1, 0x21B1, 0x01C1, 0x01C1, 0x11C1, 0x21C1, 0x31C1, 0x01D1, 0x01D1, 0x01D1, 0x01D1, 0x11D1, 0x21D1, 0x21D1, 0x01E1, 0x01E1, 0x01F1, 0x01F1, 0x0201, 0x0201, 0x0211, 0x0221, 0x0231, 0x0241, 0x0251, 0x0281, 0x0291, 0x0281, 0x0291, 0x02A1, 0x02B1, 0x02C1, 0x0321, 0x0321, 0x1321, 0x2321, 0x3321, 0x0331, 0x0331, 0x1331, 0x0341, 0x0341, 0x1341, 0x2341, 0x3341, 0x0351, 0x0361, 0x0361, 0x1361, 0x2361, 0x0371, 0x0381, 0x0391, 0x03C1, 0x03D1, 0x03E1, 0x03F1, }; /** * _sde_dbg_enable_power - use callback to turn power on for hw register access * @enable: whether to turn power on or off Loading Loading @@ -3341,7 +3415,8 @@ static void _sde_dump_reg(const char *dump_name, u32 reg_dump_flag, if (in_log) dev_info(sde_dbg_base.dev, "%s: start_offset 0x%lx len 0x%zx\n", dump_name, addr - base_addr, len_bytes); dump_name, (unsigned long)(addr - base_addr), len_bytes); len_align = (len_bytes + REG_DUMP_ALIGN - 1) / REG_DUMP_ALIGN; len_padded = len_align * REG_DUMP_ALIGN; Loading @@ -3359,7 +3434,7 @@ static void _sde_dump_reg(const char *dump_name, u32 reg_dump_flag, dev_info(sde_dbg_base.dev, "%s: start_addr:0x%pK len:0x%x reg_offset=0x%lx\n", dump_name, dump_addr, len_padded, addr - base_addr); (unsigned long)(addr - base_addr)); } else { in_mem = 0; pr_err("dump_mem: kzalloc fails!\n"); Loading @@ -3385,7 +3460,8 @@ static void _sde_dump_reg(const char *dump_name, u32 reg_dump_flag, if (in_log) dev_info(sde_dbg_base.dev, "0x%lx : %08x %08x %08x %08x\n", addr - base_addr, x0, x4, x8, xc); (unsigned long)(addr - base_addr), x0, x4, x8, xc); if (dump_addr) { dump_addr[i * 4] = x0; Loading @@ -3412,11 +3488,12 @@ static u32 _sde_dbg_get_dump_range(struct sde_dbg_reg_offset *range_node, { u32 length = 0; if ((range_node->start > range_node->end) || (range_node->end > max_offset) || (range_node->start == 0 && range_node->end == 0)) { if (range_node->start == 0 && range_node->end == 0) { length = max_offset; } else { } else if (range_node->start < max_offset) { if (range_node->end > max_offset) length = max_offset - range_node->start; else if (range_node->start < range_node->end) length = range_node->end - range_node->start; } Loading Loading @@ -3857,7 +3934,8 @@ static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[], _sde_dbg_dump_vbif_dbg_bus(&sde_dbg_base.dbgbus_vbif_rt); if (sde_dbg_base.dsi_dbg_bus || dump_all) dsi_ctrl_debug_dump(); dsi_ctrl_debug_dump(sde_dbg_base.dbgbus_dsi.entries, sde_dbg_base.dbgbus_dsi.size); if (do_panic && sde_dbg_base.panic_on_err) panic(name); Loading Loading @@ -4018,6 +4096,12 @@ static int sde_dbg_debugfs_open(struct inode *inode, struct file *file) /* non-seekable */ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); file->private_data = inode->i_private; mutex_lock(&sde_dbg_base.mutex); sde_dbg_base.cur_evt_index = 0; sde_dbg_base.evtlog->first = sde_dbg_base.evtlog->curr + 1; sde_dbg_base.evtlog->last = sde_dbg_base.evtlog->first + SDE_EVTLOG_ENTRY; mutex_unlock(&sde_dbg_base.mutex); return 0; } Loading @@ -4037,8 +4121,13 @@ static ssize_t sde_evtlog_dump_read(struct file *file, char __user *buff, if (!buff || !ppos) return -EINVAL; len = sde_evtlog_dump_to_buffer(sde_dbg_base.evtlog, evtlog_buf, SDE_EVTLOG_BUF_MAX, true); mutex_lock(&sde_dbg_base.mutex); len = sde_evtlog_dump_to_buffer(sde_dbg_base.evtlog, evtlog_buf, SDE_EVTLOG_BUF_MAX, !sde_dbg_base.cur_evt_index, true); sde_dbg_base.cur_evt_index++; mutex_unlock(&sde_dbg_base.mutex); if (len < 0 || len > count) { pr_err("len is more than user buffer size\n"); return 0; Loading Loading @@ -4228,6 +4317,329 @@ static const struct file_operations sde_evtlog_filter_fops = { .release = seq_release }; static int sde_recovery_regdump_open(struct inode *inode, struct file *file) { if (!inode || !file) return -EINVAL; /* non-seekable */ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); file->private_data = inode->i_private; /* initialize to start position */ sde_dbg_base.regbuf.rpos = 0; sde_dbg_base.regbuf.cur_blk = NULL; sde_dbg_base.regbuf.dump_done = false; return 0; } static ssize_t _sde_dbg_dump_reg_rows(u32 reg_start, void *start, int count, char *buf, int buflen) { int i; int len = 0; u32 *addr; u32 reg_offset = 0; int rows = min(count / DUMP_CLMN_COUNT, DUMP_MAX_LINES_PER_BLK); if (!start || !buf) { pr_err("invalid address for dump\n"); return len; } if (buflen < PAGE_SIZE) { pr_err("buffer too small for dump\n"); return len; } for (i = 0; i < rows; i++) { addr = start + (i * DUMP_CLMN_COUNT * sizeof(u32)); reg_offset = reg_start + (i * DUMP_CLMN_COUNT * sizeof(u32)); if (buflen < (len + DUMP_LINE_SIZE)) break; len += snprintf(buf + len, DUMP_LINE_SIZE, "0x%.8X | %.8X %.8X %.8X %.8X\n", reg_offset, addr[0], addr[1], addr[2], addr[3]); } return len; } static int _sde_dbg_recovery_dump_sub_blk(struct sde_dbg_reg_range *sub_blk, char *buf, int buflen) { int count = 0; int len = 0; if (!sub_blk || (buflen < PAGE_SIZE)) { pr_err("invalid params buflen:%d subblk valid:%d\n", buflen, sub_blk != NULL); return len; } count = (sub_blk->offset.end - sub_blk->offset.start) / (sizeof(u32)); if (count < DUMP_CLMN_COUNT) { pr_err("invalid count for register dumps :%d\n", count); return len; } len += snprintf(buf + len, DUMP_LINE_SIZE, "------------------------------------------\n"); len += snprintf(buf + len, DUMP_LINE_SIZE, "**** sub block [%s] - size:%d ****\n", sub_blk->range_name, count); len += _sde_dbg_dump_reg_rows(sub_blk->offset.start, sub_blk->reg_dump, count, buf + len, buflen - len); return len; } static int _sde_dbg_recovery_dump_reg_blk(struct sde_dbg_reg_base *blk, char *buf, int buf_size, int *out_len) { int ret = 0; int len = 0; struct sde_dbg_reg_range *sub_blk; if (buf_size < PAGE_SIZE) { pr_err("buffer too small for dump\n"); return len; } if (!blk || !strlen(blk->name)) { len += snprintf(buf + len, DUMP_LINE_SIZE, "Found one invalid block - skip dump\n"); *out_len = len; return len; } len += snprintf(buf + len, DUMP_LINE_SIZE, "******************************************\n"); len += snprintf(buf + len, DUMP_LINE_SIZE, "==========================================\n"); len += snprintf(buf + len, DUMP_LINE_SIZE, "*********** DUMP of %s block *************\n", blk->name); len += snprintf(buf + len, DUMP_LINE_SIZE, "count:%ld max-off:0x%lx has_sub_blk:%d\n", blk->cnt, blk->max_offset, !list_empty(&blk->sub_range_list)); if (list_empty(&blk->sub_range_list)) { len += _sde_dbg_dump_reg_rows(0, blk->reg_dump, blk->max_offset / sizeof(u32), buf + len, buf_size - len); } else { list_for_each_entry(sub_blk, &blk->sub_range_list, head) len += _sde_dbg_recovery_dump_sub_blk(sub_blk, buf + len, buf_size - len); } *out_len = len; return ret; } static ssize_t sde_recovery_regdump_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { ssize_t len = 0; int usize = 0; struct sde_dbg_base *dbg_base = &sde_dbg_base; struct sde_dbg_regbuf *rbuf = &dbg_base->regbuf; mutex_lock(&sde_dbg_base.mutex); if (!rbuf->dump_done && !rbuf->cur_blk) { if (!rbuf->buf) rbuf->buf = kzalloc(DUMP_BUF_SIZE, GFP_KERNEL); if (!rbuf->buf) { len = -ENOMEM; goto err; } rbuf->rpos = 0; rbuf->len = 0; rbuf->buf_size = DUMP_BUF_SIZE; rbuf->cur_blk = list_first_entry(&dbg_base->reg_base_list, struct sde_dbg_reg_base, reg_base_head); if (rbuf->cur_blk) _sde_dbg_recovery_dump_reg_blk(rbuf->cur_blk, rbuf->buf, rbuf->buf_size, &rbuf->len); pr_debug("dumping done for blk:%s len:%d\n", rbuf->cur_blk ? rbuf->cur_blk->name : "unknown", rbuf->len); } else if (rbuf->len == rbuf->rpos && rbuf->cur_blk) { rbuf->rpos = 0; rbuf->len = 0; rbuf->buf_size = DUMP_BUF_SIZE; if (rbuf->cur_blk == list_last_entry(&dbg_base->reg_base_list, struct sde_dbg_reg_base, reg_base_head)) rbuf->cur_blk = NULL; else rbuf->cur_blk = list_next_entry(rbuf->cur_blk, reg_base_head); if (rbuf->cur_blk) _sde_dbg_recovery_dump_reg_blk(rbuf->cur_blk, rbuf->buf, rbuf->buf_size, &rbuf->len); pr_debug("dumping done for blk:%s len:%d\n", rbuf->cur_blk ? rbuf->cur_blk->name : "unknown", rbuf->len); } if ((rbuf->len - rbuf->rpos) > 0) { usize = ((rbuf->len - rbuf->rpos) > count) ? count : rbuf->len - rbuf->rpos; if (copy_to_user(ubuf, rbuf->buf + rbuf->rpos, usize)) { len = -EFAULT; goto err; } len = usize; rbuf->rpos += usize; *ppos += usize; } if (!len && rbuf->buf) rbuf->dump_done = true; err: mutex_unlock(&sde_dbg_base.mutex); return len; } static const struct file_operations sde_recovery_reg_fops = { .open = sde_recovery_regdump_open, .read = sde_recovery_regdump_read, }; static int sde_recovery_dbgbus_dump_open(struct inode *inode, struct file *file) { if (!inode || !file) return -EINVAL; /* non-seekable */ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); file->private_data = inode->i_private; mutex_lock(&sde_dbg_base.mutex); sde_dbg_base.dbgbus_dump_idx = 0; mutex_unlock(&sde_dbg_base.mutex); return 0; } static ssize_t sde_recovery_dbgbus_dump_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { ssize_t len = 0; char evtlog_buf[SDE_EVTLOG_BUF_MAX]; u32 *data; struct sde_dbg_sde_debug_bus *bus; mutex_lock(&sde_dbg_base.mutex); bus = &sde_dbg_base.dbgbus_sde; if (!bus->cmn.dumped_content || !bus->cmn.entries_size) goto dump_done; if (sde_dbg_base.dbgbus_dump_idx <= ((bus->cmn.entries_size - 1) * DUMP_CLMN_COUNT)) { data = &bus->cmn.dumped_content[ sde_dbg_base.dbgbus_dump_idx]; len = snprintf(evtlog_buf, SDE_EVTLOG_BUF_MAX, "0x%.8X | %.8X %.8X %.8X %.8X\n", sde_dbg_base.dbgbus_dump_idx, data[0], data[1], data[2], data[3]); sde_dbg_base.dbgbus_dump_idx += DUMP_CLMN_COUNT; if ((count < len) || copy_to_user(buff, evtlog_buf, len)) { len = -EFAULT; goto dump_done; } *ppos += len; } dump_done: mutex_unlock(&sde_dbg_base.mutex); return len; } static const struct file_operations sde_recovery_dbgbus_fops = { .open = sde_recovery_dbgbus_dump_open, .read = sde_recovery_dbgbus_dump_read, }; static int sde_recovery_vbif_dbgbus_dump_open(struct inode *inode, struct file *file) { if (!inode || !file) return -EINVAL; /* non-seekable */ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); file->private_data = inode->i_private; mutex_lock(&sde_dbg_base.mutex); sde_dbg_base.vbif_dbgbus_dump_idx = 0; mutex_unlock(&sde_dbg_base.mutex); return 0; } static ssize_t sde_recovery_vbif_dbgbus_dump_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { ssize_t len = 0; char evtlog_buf[SDE_EVTLOG_BUF_MAX]; int i; u32 *data; u32 list_size = 0; struct vbif_debug_bus_entry *head; struct sde_dbg_vbif_debug_bus *bus; mutex_lock(&sde_dbg_base.mutex); bus = &sde_dbg_base.dbgbus_vbif_rt; if (!bus->cmn.dumped_content || !bus->cmn.entries_size) goto dump_done; /* calculate total number of test point */ for (i = 0; i < bus->cmn.entries_size; i++) { head = bus->entries + i; list_size += (head->block_cnt * head->test_pnt_cnt); } /* 4 entries for each test point*/ list_size *= DUMP_CLMN_COUNT; if (sde_dbg_base.vbif_dbgbus_dump_idx < list_size) { data = &bus->cmn.dumped_content[ sde_dbg_base.vbif_dbgbus_dump_idx]; len = snprintf(evtlog_buf, SDE_EVTLOG_BUF_MAX, "0x%.8X | %.8X %.8X %.8X %.8X\n", sde_dbg_base.vbif_dbgbus_dump_idx, data[0], data[1], data[2], data[3]); sde_dbg_base.vbif_dbgbus_dump_idx += DUMP_CLMN_COUNT; if ((count < len) || copy_to_user(buff, evtlog_buf, len)) { len = -EFAULT; goto dump_done; } *ppos += len; } dump_done: mutex_unlock(&sde_dbg_base.mutex); return len; } static const struct file_operations sde_recovery_vbif_dbgbus_fops = { .open = sde_recovery_vbif_dbgbus_dump_open, .read = sde_recovery_vbif_dbgbus_dump_read, }; /** * sde_dbg_reg_base_release - release allocated reg dump file private data * @inode: debugfs inode Loading Loading @@ -4256,6 +4668,37 @@ static int sde_dbg_reg_base_release(struct inode *inode, struct file *file) return 0; } /** * sde_dbg_reg_base_is_valid_range - verify if requested memory range is valid * @off: address offset in bytes * @cnt: memory size in bytes * Return: true if valid; false otherwise */ static bool sde_dbg_reg_base_is_valid_range(u32 off, u32 cnt) { static struct sde_dbg_base *dbg_base = &sde_dbg_base; struct sde_dbg_reg_range *node; struct sde_dbg_reg_base *base; pr_debug("check offset=0x%x cnt=0x%x\n", off, cnt); list_for_each_entry(base, &dbg_base->reg_base_list, reg_base_head) { list_for_each_entry(node, &base->sub_range_list, head) { pr_debug("%s: start=0x%x end=0x%x\n", node->range_name, node->offset.start, node->offset.end); if (node->offset.start <= off && off <= node->offset.end && off + cnt <= node->offset.end) { pr_debug("valid range requested\n"); return true; } } } pr_err("invalid range requested\n"); return false; } /** * sde_dbg_reg_base_offset_write - set new offset and len to debugfs reg base Loading Loading @@ -4302,6 +4745,9 @@ static ssize_t sde_dbg_reg_base_offset_write(struct file *file, if (cnt == 0) return -EINVAL; if (!sde_dbg_reg_base_is_valid_range(off, cnt)) return -EINVAL; mutex_lock(&sde_dbg_base.mutex); dbg->off = off; dbg->cnt = cnt; Loading Loading @@ -4556,6 +5002,12 @@ int sde_dbg_debugfs_register(struct dentry *debugfs_root) &sde_dbg_base.panic_on_err); debugfs_create_u32("reg_dump", 0600, debugfs_root, &sde_dbg_base.enable_reg_dump); debugfs_create_file("recovery_reg", 0400, debugfs_root, NULL, &sde_recovery_reg_fops); debugfs_create_file("recovery_dbgbus", 0400, debugfs_root, NULL, &sde_recovery_dbgbus_fops); debugfs_create_file("recovery_vbif_dbgbus", 0400, debugfs_root, NULL, &sde_recovery_vbif_dbgbus_fops); if (dbg->dbgbus_sde.entries) { dbg->dbgbus_sde.cmn.name = DBGBUS_NAME_SDE; Loading Loading @@ -4609,6 +5061,8 @@ void sde_dbg_init_dbg_buses(u32 hwversion) dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998; dbg->dbgbus_vbif_rt.cmn.entries_size = ARRAY_SIZE(vbif_dbg_bus_msm8998); dbg->dbgbus_dsi.entries = NULL; dbg->dbgbus_dsi.size = 0; } else if (IS_SDM845_TARGET(hwversion) || IS_SDM670_TARGET(hwversion)) { dbg->dbgbus_sde.entries = dbg_bus_sde_sdm845; dbg->dbgbus_sde.cmn.entries_size = Loading @@ -4619,7 +5073,9 @@ void sde_dbg_init_dbg_buses(u32 hwversion) dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998; dbg->dbgbus_vbif_rt.cmn.entries_size = ARRAY_SIZE(vbif_dbg_bus_msm8998); } else if (IS_SM8150_TARGET(hwversion)) { dbg->dbgbus_dsi.entries = dsi_dbg_bus_sdm845; dbg->dbgbus_dsi.size = ARRAY_SIZE(dsi_dbg_bus_sdm845); } else if (IS_SM8150_TARGET(hwversion) || IS_SM6150_TARGET(hwversion)) { dbg->dbgbus_sde.entries = dbg_bus_sde_sm8150; dbg->dbgbus_sde.cmn.entries_size = ARRAY_SIZE(dbg_bus_sde_sm8150); Loading @@ -4628,6 +5084,8 @@ void sde_dbg_init_dbg_buses(u32 hwversion) dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998; dbg->dbgbus_vbif_rt.cmn.entries_size = ARRAY_SIZE(vbif_dbg_bus_msm8998); dbg->dbgbus_dsi.entries = NULL; dbg->dbgbus_dsi.size = 0; } else { pr_err("unsupported chipset id %X\n", hwversion); } Loading Loading @@ -4655,6 +5113,7 @@ int sde_dbg_init(struct device *dev, struct sde_dbg_power_ctrl *power_ctrl) sde_dbg_base.work_panic = false; sde_dbg_base.panic_on_err = DEFAULT_PANIC; sde_dbg_base.enable_reg_dump = DEFAULT_REGDUMP; memset(&sde_dbg_base.regbuf, 0, sizeof(sde_dbg_base.regbuf)); pr_info("evtlog_status: enable:%d, panic:%d, dump:%d\n", sde_dbg_base.evtlog->enable, sde_dbg_base.panic_on_err, Loading Loading @@ -4688,6 +5147,8 @@ static void sde_dbg_reg_base_destroy(void) */ void sde_dbg_destroy(void) { kfree(sde_dbg_base.regbuf.buf); memset(&sde_dbg_base.regbuf, 0, sizeof(sde_dbg_base.regbuf)); _sde_dbg_debugfs_destroy(); sde_dbg_base_evtlog = NULL; sde_evtlog_destroy(sde_dbg_base.evtlog); Loading drivers/gpu/drm/msm/sde_dbg.h +13 −4 Original line number Diff line number Diff line Loading @@ -201,11 +201,12 @@ bool sde_evtlog_is_enabled(struct sde_dbg_evtlog *evtlog, u32 flag); * @evtlog_buf: target buffer to print into * @evtlog_buf_size: size of target buffer * @update_last_entry: whether or not to stop at most recent entry * @full_dump: whether to dump full or to limit print entries * Returns: number of bytes written to buffer */ ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, char *evtlog_buf, ssize_t evtlog_buf_size, bool update_last_entry); bool update_last_entry, bool full_dump); /** * sde_dbg_init_dbg_buses - initialize debug bus dumping support for the chipset Loading Loading @@ -329,16 +330,24 @@ void sde_evtlog_set_filter(struct sde_dbg_evtlog *evtlog, char *filter); int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, int index, char *buf, size_t bufsz); #ifndef CONFIG_DRM_SDE_RSC static inline void sde_rsc_debug_dump(u32 mux_sel) { } #else /** * sde_rsc_debug_dump - sde rsc debug dump status * @mux_sel: select mux on rsc debug bus * @mux_sel:» select mux on rsc debug bus */ void sde_rsc_debug_dump(u32 mux_sel); #endif /** * dsi_ctrl_debug_dump - dump dsi debug dump status * @entries: array of debug bus control values * @size: size of the debug bus control array */ void dsi_ctrl_debug_dump(void); void dsi_ctrl_debug_dump(u32 *entries, u32 size); #else static inline struct sde_dbg_evtlog *sde_evtlog_init(void) Loading Loading @@ -430,7 +439,7 @@ static inline void sde_rsc_debug_dump(u32 mux_sel) { } static inline void dsi_ctrl_debug_dump(void) static inline void dsi_ctrl_debug_dump(u32 entries, u32 size) { } Loading drivers/gpu/drm/msm/sde_dbg_evtlog.c +8 −7 Original line number Diff line number Diff line Loading @@ -101,8 +101,10 @@ void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, const char *name, int line, /* always dump the last entries which are not dumped yet */ static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog, bool update_last_entry) bool update_last_entry, bool full_dump) { int max_entries = full_dump ? SDE_EVTLOG_ENTRY : SDE_EVTLOG_PRINT_ENTRY; if (!evtlog) return false; Loading @@ -120,12 +122,11 @@ static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog, evtlog->last_dump += SDE_EVTLOG_ENTRY; } if ((evtlog->last_dump - evtlog->first) > SDE_EVTLOG_PRINT_ENTRY) { if ((evtlog->last_dump - evtlog->first) > max_entries) { pr_info("evtlog skipping %d entries, last=%d\n", evtlog->last_dump - evtlog->first - SDE_EVTLOG_PRINT_ENTRY, evtlog->last_dump - 1); evtlog->first = evtlog->last_dump - SDE_EVTLOG_PRINT_ENTRY; max_entries, evtlog->last_dump - 1); evtlog->first = evtlog->last_dump - max_entries; } evtlog->next = evtlog->first + 1; Loading @@ -134,7 +135,7 @@ static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog, ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, char *evtlog_buf, ssize_t evtlog_buf_size, bool update_last_entry) bool update_last_entry, bool full_dump) { int i; ssize_t off = 0; Loading @@ -147,7 +148,7 @@ ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, spin_lock_irqsave(&evtlog->spin_lock, flags); /* update markers, exit if nothing to print */ if (!_sde_evtlog_dump_calc_range(evtlog, update_last_entry)) if (!_sde_evtlog_dump_calc_range(evtlog, update_last_entry, full_dump)) goto exit; log = &evtlog->logs[evtlog->first % SDE_EVTLOG_ENTRY]; Loading drivers/gpu/drm/msm/sde_edid_parser.c +5 −4 Original line number Diff line number Diff line Loading @@ -172,8 +172,9 @@ static const u8 *_sde_edid_find_block(const u8 *in_buf, u32 start_offset, * * edid buffer 1, byte 2 being 0 means no non-DTD/DATA block * collection present and no DTD data present. */ if ((dbc_offset == 0) || (dbc_offset == 4)) { SDE_ERROR("EDID: no DTD or non-DTD data present\n"); SDE_EDID_DEBUG("EDID: no DTD or non-DTD data present\n"); return NULL; } Loading Loading @@ -376,7 +377,7 @@ struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl) edid_ext = sde_find_cea_extension(edid_ctrl->edid); if (!edid_ext) { SDE_ERROR("no cea extension\n"); SDE_DEBUG("no cea extension\n"); return; } Loading Loading @@ -545,7 +546,7 @@ int _sde_edid_update_modes(struct drm_connector *connector, SDE_EDID_DEBUG("%s +", __func__); if (edid_ctrl->edid) { drm_mode_connector_update_edid_property(connector, drm_connector_update_edid_property(connector, edid_ctrl->edid); rc = drm_add_edid_modes(connector, edid_ctrl->edid); Loading @@ -555,7 +556,7 @@ int _sde_edid_update_modes(struct drm_connector *connector, return rc; } drm_mode_connector_update_edid_property(connector, NULL); drm_connector_update_edid_property(connector, NULL); SDE_EDID_DEBUG("%s null edid -", __func__); return rc; } Loading drivers/gpu/drm/msm/sde_hdcp.h +7 −4 Original line number Diff line number Diff line Loading @@ -33,8 +33,9 @@ enum sde_hdcp_state { enum sde_hdcp_version { HDCP_VERSION_NONE, HDCP_VERSION_1X, HDCP_VERSION_2P2 HDCP_VERSION_1X = BIT(0), HDCP_VERSION_2P2 = BIT(1), HDCP_VERSION_MAX = BIT(2), }; struct sde_hdcp_init_data { Loading Loading @@ -64,6 +65,8 @@ struct sde_hdcp_ops { int (*reauthenticate)(void *input); int (*authenticate)(void *hdcp_ctrl); bool (*feature_supported)(void *input); void (*force_encryption)(void *input, bool enable); bool (*sink_support)(void *input); void (*off)(void *hdcp_ctrl); }; Loading @@ -90,8 +93,8 @@ static inline const char *sde_hdcp_version(enum sde_hdcp_version hdcp_version) void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data); void sde_hdcp_1x_deinit(void *input); struct sde_hdcp_ops *sde_hdcp_1x_start(void *input); struct sde_hdcp_ops *sde_hdcp_1x_get(void *input); void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data); void sde_dp_hdcp2p2_deinit(void *input); struct sde_hdcp_ops *sde_dp_hdcp2p2_start(void *input); struct sde_hdcp_ops *sde_dp_hdcp2p2_get(void *input); #endif /* __SDE_HDCP_H__ */ Loading
drivers/gpu/drm/msm/sde_dbg.c +473 −12 Original line number Diff line number Diff line Loading @@ -67,6 +67,11 @@ #define DBG_CTRL_RESET_HW_PANIC BIT(2) #define DBG_CTRL_MAX BIT(3) #define DUMP_BUF_SIZE (4096 * 512) #define DUMP_CLMN_COUNT 4 #define DUMP_LINE_SIZE 256 #define DUMP_MAX_LINES_PER_BLK 512 /** * struct sde_dbg_reg_offset - tracking for start and end of region * @start: start offset Loading Loading @@ -162,6 +167,29 @@ struct sde_dbg_vbif_debug_bus { struct vbif_debug_bus_entry *entries; }; struct sde_dbg_dsi_debug_bus { u32 *entries; u32 size; }; /** * struct sde_dbg_regbuf - wraps buffer and tracking params for register dumps * @buf: pointer to allocated memory for storing register dumps in hw recovery * @buf_size: size of the memory allocated * @len: size of the dump data valid in the buffer * @rpos: cursor points to the buffer position read by client * @dump_done: to indicate if dumping to user memory is complete * @cur_blk: points to the current sde_dbg_reg_base block */ struct sde_dbg_regbuf { char *buf; int buf_size; int len; int rpos; int dump_done; struct sde_dbg_reg_base *cur_blk; }; /** * struct sde_dbg_base - global sde debug base structure * @evtlog: event log instance Loading @@ -178,6 +206,10 @@ struct sde_dbg_vbif_debug_bus { * @dbgbus_vbif_rt: debug bus structure for the realtime vbif * @dump_all: dump all entries in register dump * @dsi_dbg_bus: dump dsi debug bus register * @regbuf: buffer data to track the register dumping in hw recovery * @cur_evt_index: index used for tracking event logs dump in hw recovery * @dbgbus_dump_idx: index used for tracking dbg-bus dump in hw recovery * @vbif_dbgbus_dump_idx: index for tracking vbif dumps in hw recovery */ static struct sde_dbg_base { struct sde_dbg_evtlog *evtlog; Loading @@ -195,9 +227,15 @@ static struct sde_dbg_base { struct sde_dbg_sde_debug_bus dbgbus_sde; struct sde_dbg_vbif_debug_bus dbgbus_vbif_rt; struct sde_dbg_dsi_debug_bus dbgbus_dsi; bool dump_all; bool dsi_dbg_bus; u32 debugfs_ctrl; struct sde_dbg_regbuf regbuf; u32 cur_evt_index; u32 dbgbus_dump_idx; u32 vbif_dbgbus_dump_idx; } sde_dbg_base; /* sde_dbg_base_evtlog - global pointer to main sde event log for macro use */ Loading Loading @@ -3292,6 +3330,42 @@ static struct vbif_debug_bus_entry vbif_dbg_bus_msm8998[] = { {0x21c, 0x214, 0, 14, 0, 0xc}, /* xin blocks - clock side */ }; static u32 dsi_dbg_bus_sdm845[] = { 0x0001, 0x1001, 0x0001, 0x0011, 0x1021, 0x0021, 0x0031, 0x0041, 0x0051, 0x0061, 0x3061, 0x0061, 0x2061, 0x2061, 0x1061, 0x1061, 0x1061, 0x0071, 0x0071, 0x0071, 0x0081, 0x0081, 0x00A1, 0x00A1, 0x10A1, 0x20A1, 0x30A1, 0x10A1, 0x10A1, 0x30A1, 0x20A1, 0x00B1, 0x00C1, 0x00C1, 0x10C1, 0x20C1, 0x30C1, 0x00D1, 0x00D1, 0x20D1, 0x30D1, 0x00E1, 0x00E1, 0x00E1, 0x00F1, 0x00F1, 0x0101, 0x0101, 0x1101, 0x2101, 0x3101, 0x0111, 0x0141, 0x1141, 0x0141, 0x1141, 0x1141, 0x0151, 0x0151, 0x1151, 0x2151, 0x3151, 0x0161, 0x0161, 0x1161, 0x0171, 0x0171, 0x0181, 0x0181, 0x0191, 0x0191, 0x01A1, 0x01A1, 0x01B1, 0x01B1, 0x11B1, 0x21B1, 0x01C1, 0x01C1, 0x11C1, 0x21C1, 0x31C1, 0x01D1, 0x01D1, 0x01D1, 0x01D1, 0x11D1, 0x21D1, 0x21D1, 0x01E1, 0x01E1, 0x01F1, 0x01F1, 0x0201, 0x0201, 0x0211, 0x0221, 0x0231, 0x0241, 0x0251, 0x0281, 0x0291, 0x0281, 0x0291, 0x02A1, 0x02B1, 0x02C1, 0x0321, 0x0321, 0x1321, 0x2321, 0x3321, 0x0331, 0x0331, 0x1331, 0x0341, 0x0341, 0x1341, 0x2341, 0x3341, 0x0351, 0x0361, 0x0361, 0x1361, 0x2361, 0x0371, 0x0381, 0x0391, 0x03C1, 0x03D1, 0x03E1, 0x03F1, }; /** * _sde_dbg_enable_power - use callback to turn power on for hw register access * @enable: whether to turn power on or off Loading Loading @@ -3341,7 +3415,8 @@ static void _sde_dump_reg(const char *dump_name, u32 reg_dump_flag, if (in_log) dev_info(sde_dbg_base.dev, "%s: start_offset 0x%lx len 0x%zx\n", dump_name, addr - base_addr, len_bytes); dump_name, (unsigned long)(addr - base_addr), len_bytes); len_align = (len_bytes + REG_DUMP_ALIGN - 1) / REG_DUMP_ALIGN; len_padded = len_align * REG_DUMP_ALIGN; Loading @@ -3359,7 +3434,7 @@ static void _sde_dump_reg(const char *dump_name, u32 reg_dump_flag, dev_info(sde_dbg_base.dev, "%s: start_addr:0x%pK len:0x%x reg_offset=0x%lx\n", dump_name, dump_addr, len_padded, addr - base_addr); (unsigned long)(addr - base_addr)); } else { in_mem = 0; pr_err("dump_mem: kzalloc fails!\n"); Loading @@ -3385,7 +3460,8 @@ static void _sde_dump_reg(const char *dump_name, u32 reg_dump_flag, if (in_log) dev_info(sde_dbg_base.dev, "0x%lx : %08x %08x %08x %08x\n", addr - base_addr, x0, x4, x8, xc); (unsigned long)(addr - base_addr), x0, x4, x8, xc); if (dump_addr) { dump_addr[i * 4] = x0; Loading @@ -3412,11 +3488,12 @@ static u32 _sde_dbg_get_dump_range(struct sde_dbg_reg_offset *range_node, { u32 length = 0; if ((range_node->start > range_node->end) || (range_node->end > max_offset) || (range_node->start == 0 && range_node->end == 0)) { if (range_node->start == 0 && range_node->end == 0) { length = max_offset; } else { } else if (range_node->start < max_offset) { if (range_node->end > max_offset) length = max_offset - range_node->start; else if (range_node->start < range_node->end) length = range_node->end - range_node->start; } Loading Loading @@ -3857,7 +3934,8 @@ static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[], _sde_dbg_dump_vbif_dbg_bus(&sde_dbg_base.dbgbus_vbif_rt); if (sde_dbg_base.dsi_dbg_bus || dump_all) dsi_ctrl_debug_dump(); dsi_ctrl_debug_dump(sde_dbg_base.dbgbus_dsi.entries, sde_dbg_base.dbgbus_dsi.size); if (do_panic && sde_dbg_base.panic_on_err) panic(name); Loading Loading @@ -4018,6 +4096,12 @@ static int sde_dbg_debugfs_open(struct inode *inode, struct file *file) /* non-seekable */ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); file->private_data = inode->i_private; mutex_lock(&sde_dbg_base.mutex); sde_dbg_base.cur_evt_index = 0; sde_dbg_base.evtlog->first = sde_dbg_base.evtlog->curr + 1; sde_dbg_base.evtlog->last = sde_dbg_base.evtlog->first + SDE_EVTLOG_ENTRY; mutex_unlock(&sde_dbg_base.mutex); return 0; } Loading @@ -4037,8 +4121,13 @@ static ssize_t sde_evtlog_dump_read(struct file *file, char __user *buff, if (!buff || !ppos) return -EINVAL; len = sde_evtlog_dump_to_buffer(sde_dbg_base.evtlog, evtlog_buf, SDE_EVTLOG_BUF_MAX, true); mutex_lock(&sde_dbg_base.mutex); len = sde_evtlog_dump_to_buffer(sde_dbg_base.evtlog, evtlog_buf, SDE_EVTLOG_BUF_MAX, !sde_dbg_base.cur_evt_index, true); sde_dbg_base.cur_evt_index++; mutex_unlock(&sde_dbg_base.mutex); if (len < 0 || len > count) { pr_err("len is more than user buffer size\n"); return 0; Loading Loading @@ -4228,6 +4317,329 @@ static const struct file_operations sde_evtlog_filter_fops = { .release = seq_release }; static int sde_recovery_regdump_open(struct inode *inode, struct file *file) { if (!inode || !file) return -EINVAL; /* non-seekable */ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); file->private_data = inode->i_private; /* initialize to start position */ sde_dbg_base.regbuf.rpos = 0; sde_dbg_base.regbuf.cur_blk = NULL; sde_dbg_base.regbuf.dump_done = false; return 0; } static ssize_t _sde_dbg_dump_reg_rows(u32 reg_start, void *start, int count, char *buf, int buflen) { int i; int len = 0; u32 *addr; u32 reg_offset = 0; int rows = min(count / DUMP_CLMN_COUNT, DUMP_MAX_LINES_PER_BLK); if (!start || !buf) { pr_err("invalid address for dump\n"); return len; } if (buflen < PAGE_SIZE) { pr_err("buffer too small for dump\n"); return len; } for (i = 0; i < rows; i++) { addr = start + (i * DUMP_CLMN_COUNT * sizeof(u32)); reg_offset = reg_start + (i * DUMP_CLMN_COUNT * sizeof(u32)); if (buflen < (len + DUMP_LINE_SIZE)) break; len += snprintf(buf + len, DUMP_LINE_SIZE, "0x%.8X | %.8X %.8X %.8X %.8X\n", reg_offset, addr[0], addr[1], addr[2], addr[3]); } return len; } static int _sde_dbg_recovery_dump_sub_blk(struct sde_dbg_reg_range *sub_blk, char *buf, int buflen) { int count = 0; int len = 0; if (!sub_blk || (buflen < PAGE_SIZE)) { pr_err("invalid params buflen:%d subblk valid:%d\n", buflen, sub_blk != NULL); return len; } count = (sub_blk->offset.end - sub_blk->offset.start) / (sizeof(u32)); if (count < DUMP_CLMN_COUNT) { pr_err("invalid count for register dumps :%d\n", count); return len; } len += snprintf(buf + len, DUMP_LINE_SIZE, "------------------------------------------\n"); len += snprintf(buf + len, DUMP_LINE_SIZE, "**** sub block [%s] - size:%d ****\n", sub_blk->range_name, count); len += _sde_dbg_dump_reg_rows(sub_blk->offset.start, sub_blk->reg_dump, count, buf + len, buflen - len); return len; } static int _sde_dbg_recovery_dump_reg_blk(struct sde_dbg_reg_base *blk, char *buf, int buf_size, int *out_len) { int ret = 0; int len = 0; struct sde_dbg_reg_range *sub_blk; if (buf_size < PAGE_SIZE) { pr_err("buffer too small for dump\n"); return len; } if (!blk || !strlen(blk->name)) { len += snprintf(buf + len, DUMP_LINE_SIZE, "Found one invalid block - skip dump\n"); *out_len = len; return len; } len += snprintf(buf + len, DUMP_LINE_SIZE, "******************************************\n"); len += snprintf(buf + len, DUMP_LINE_SIZE, "==========================================\n"); len += snprintf(buf + len, DUMP_LINE_SIZE, "*********** DUMP of %s block *************\n", blk->name); len += snprintf(buf + len, DUMP_LINE_SIZE, "count:%ld max-off:0x%lx has_sub_blk:%d\n", blk->cnt, blk->max_offset, !list_empty(&blk->sub_range_list)); if (list_empty(&blk->sub_range_list)) { len += _sde_dbg_dump_reg_rows(0, blk->reg_dump, blk->max_offset / sizeof(u32), buf + len, buf_size - len); } else { list_for_each_entry(sub_blk, &blk->sub_range_list, head) len += _sde_dbg_recovery_dump_sub_blk(sub_blk, buf + len, buf_size - len); } *out_len = len; return ret; } static ssize_t sde_recovery_regdump_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { ssize_t len = 0; int usize = 0; struct sde_dbg_base *dbg_base = &sde_dbg_base; struct sde_dbg_regbuf *rbuf = &dbg_base->regbuf; mutex_lock(&sde_dbg_base.mutex); if (!rbuf->dump_done && !rbuf->cur_blk) { if (!rbuf->buf) rbuf->buf = kzalloc(DUMP_BUF_SIZE, GFP_KERNEL); if (!rbuf->buf) { len = -ENOMEM; goto err; } rbuf->rpos = 0; rbuf->len = 0; rbuf->buf_size = DUMP_BUF_SIZE; rbuf->cur_blk = list_first_entry(&dbg_base->reg_base_list, struct sde_dbg_reg_base, reg_base_head); if (rbuf->cur_blk) _sde_dbg_recovery_dump_reg_blk(rbuf->cur_blk, rbuf->buf, rbuf->buf_size, &rbuf->len); pr_debug("dumping done for blk:%s len:%d\n", rbuf->cur_blk ? rbuf->cur_blk->name : "unknown", rbuf->len); } else if (rbuf->len == rbuf->rpos && rbuf->cur_blk) { rbuf->rpos = 0; rbuf->len = 0; rbuf->buf_size = DUMP_BUF_SIZE; if (rbuf->cur_blk == list_last_entry(&dbg_base->reg_base_list, struct sde_dbg_reg_base, reg_base_head)) rbuf->cur_blk = NULL; else rbuf->cur_blk = list_next_entry(rbuf->cur_blk, reg_base_head); if (rbuf->cur_blk) _sde_dbg_recovery_dump_reg_blk(rbuf->cur_blk, rbuf->buf, rbuf->buf_size, &rbuf->len); pr_debug("dumping done for blk:%s len:%d\n", rbuf->cur_blk ? rbuf->cur_blk->name : "unknown", rbuf->len); } if ((rbuf->len - rbuf->rpos) > 0) { usize = ((rbuf->len - rbuf->rpos) > count) ? count : rbuf->len - rbuf->rpos; if (copy_to_user(ubuf, rbuf->buf + rbuf->rpos, usize)) { len = -EFAULT; goto err; } len = usize; rbuf->rpos += usize; *ppos += usize; } if (!len && rbuf->buf) rbuf->dump_done = true; err: mutex_unlock(&sde_dbg_base.mutex); return len; } static const struct file_operations sde_recovery_reg_fops = { .open = sde_recovery_regdump_open, .read = sde_recovery_regdump_read, }; static int sde_recovery_dbgbus_dump_open(struct inode *inode, struct file *file) { if (!inode || !file) return -EINVAL; /* non-seekable */ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); file->private_data = inode->i_private; mutex_lock(&sde_dbg_base.mutex); sde_dbg_base.dbgbus_dump_idx = 0; mutex_unlock(&sde_dbg_base.mutex); return 0; } static ssize_t sde_recovery_dbgbus_dump_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { ssize_t len = 0; char evtlog_buf[SDE_EVTLOG_BUF_MAX]; u32 *data; struct sde_dbg_sde_debug_bus *bus; mutex_lock(&sde_dbg_base.mutex); bus = &sde_dbg_base.dbgbus_sde; if (!bus->cmn.dumped_content || !bus->cmn.entries_size) goto dump_done; if (sde_dbg_base.dbgbus_dump_idx <= ((bus->cmn.entries_size - 1) * DUMP_CLMN_COUNT)) { data = &bus->cmn.dumped_content[ sde_dbg_base.dbgbus_dump_idx]; len = snprintf(evtlog_buf, SDE_EVTLOG_BUF_MAX, "0x%.8X | %.8X %.8X %.8X %.8X\n", sde_dbg_base.dbgbus_dump_idx, data[0], data[1], data[2], data[3]); sde_dbg_base.dbgbus_dump_idx += DUMP_CLMN_COUNT; if ((count < len) || copy_to_user(buff, evtlog_buf, len)) { len = -EFAULT; goto dump_done; } *ppos += len; } dump_done: mutex_unlock(&sde_dbg_base.mutex); return len; } static const struct file_operations sde_recovery_dbgbus_fops = { .open = sde_recovery_dbgbus_dump_open, .read = sde_recovery_dbgbus_dump_read, }; static int sde_recovery_vbif_dbgbus_dump_open(struct inode *inode, struct file *file) { if (!inode || !file) return -EINVAL; /* non-seekable */ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); file->private_data = inode->i_private; mutex_lock(&sde_dbg_base.mutex); sde_dbg_base.vbif_dbgbus_dump_idx = 0; mutex_unlock(&sde_dbg_base.mutex); return 0; } static ssize_t sde_recovery_vbif_dbgbus_dump_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { ssize_t len = 0; char evtlog_buf[SDE_EVTLOG_BUF_MAX]; int i; u32 *data; u32 list_size = 0; struct vbif_debug_bus_entry *head; struct sde_dbg_vbif_debug_bus *bus; mutex_lock(&sde_dbg_base.mutex); bus = &sde_dbg_base.dbgbus_vbif_rt; if (!bus->cmn.dumped_content || !bus->cmn.entries_size) goto dump_done; /* calculate total number of test point */ for (i = 0; i < bus->cmn.entries_size; i++) { head = bus->entries + i; list_size += (head->block_cnt * head->test_pnt_cnt); } /* 4 entries for each test point*/ list_size *= DUMP_CLMN_COUNT; if (sde_dbg_base.vbif_dbgbus_dump_idx < list_size) { data = &bus->cmn.dumped_content[ sde_dbg_base.vbif_dbgbus_dump_idx]; len = snprintf(evtlog_buf, SDE_EVTLOG_BUF_MAX, "0x%.8X | %.8X %.8X %.8X %.8X\n", sde_dbg_base.vbif_dbgbus_dump_idx, data[0], data[1], data[2], data[3]); sde_dbg_base.vbif_dbgbus_dump_idx += DUMP_CLMN_COUNT; if ((count < len) || copy_to_user(buff, evtlog_buf, len)) { len = -EFAULT; goto dump_done; } *ppos += len; } dump_done: mutex_unlock(&sde_dbg_base.mutex); return len; } static const struct file_operations sde_recovery_vbif_dbgbus_fops = { .open = sde_recovery_vbif_dbgbus_dump_open, .read = sde_recovery_vbif_dbgbus_dump_read, }; /** * sde_dbg_reg_base_release - release allocated reg dump file private data * @inode: debugfs inode Loading Loading @@ -4256,6 +4668,37 @@ static int sde_dbg_reg_base_release(struct inode *inode, struct file *file) return 0; } /** * sde_dbg_reg_base_is_valid_range - verify if requested memory range is valid * @off: address offset in bytes * @cnt: memory size in bytes * Return: true if valid; false otherwise */ static bool sde_dbg_reg_base_is_valid_range(u32 off, u32 cnt) { static struct sde_dbg_base *dbg_base = &sde_dbg_base; struct sde_dbg_reg_range *node; struct sde_dbg_reg_base *base; pr_debug("check offset=0x%x cnt=0x%x\n", off, cnt); list_for_each_entry(base, &dbg_base->reg_base_list, reg_base_head) { list_for_each_entry(node, &base->sub_range_list, head) { pr_debug("%s: start=0x%x end=0x%x\n", node->range_name, node->offset.start, node->offset.end); if (node->offset.start <= off && off <= node->offset.end && off + cnt <= node->offset.end) { pr_debug("valid range requested\n"); return true; } } } pr_err("invalid range requested\n"); return false; } /** * sde_dbg_reg_base_offset_write - set new offset and len to debugfs reg base Loading Loading @@ -4302,6 +4745,9 @@ static ssize_t sde_dbg_reg_base_offset_write(struct file *file, if (cnt == 0) return -EINVAL; if (!sde_dbg_reg_base_is_valid_range(off, cnt)) return -EINVAL; mutex_lock(&sde_dbg_base.mutex); dbg->off = off; dbg->cnt = cnt; Loading Loading @@ -4556,6 +5002,12 @@ int sde_dbg_debugfs_register(struct dentry *debugfs_root) &sde_dbg_base.panic_on_err); debugfs_create_u32("reg_dump", 0600, debugfs_root, &sde_dbg_base.enable_reg_dump); debugfs_create_file("recovery_reg", 0400, debugfs_root, NULL, &sde_recovery_reg_fops); debugfs_create_file("recovery_dbgbus", 0400, debugfs_root, NULL, &sde_recovery_dbgbus_fops); debugfs_create_file("recovery_vbif_dbgbus", 0400, debugfs_root, NULL, &sde_recovery_vbif_dbgbus_fops); if (dbg->dbgbus_sde.entries) { dbg->dbgbus_sde.cmn.name = DBGBUS_NAME_SDE; Loading Loading @@ -4609,6 +5061,8 @@ void sde_dbg_init_dbg_buses(u32 hwversion) dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998; dbg->dbgbus_vbif_rt.cmn.entries_size = ARRAY_SIZE(vbif_dbg_bus_msm8998); dbg->dbgbus_dsi.entries = NULL; dbg->dbgbus_dsi.size = 0; } else if (IS_SDM845_TARGET(hwversion) || IS_SDM670_TARGET(hwversion)) { dbg->dbgbus_sde.entries = dbg_bus_sde_sdm845; dbg->dbgbus_sde.cmn.entries_size = Loading @@ -4619,7 +5073,9 @@ void sde_dbg_init_dbg_buses(u32 hwversion) dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998; dbg->dbgbus_vbif_rt.cmn.entries_size = ARRAY_SIZE(vbif_dbg_bus_msm8998); } else if (IS_SM8150_TARGET(hwversion)) { dbg->dbgbus_dsi.entries = dsi_dbg_bus_sdm845; dbg->dbgbus_dsi.size = ARRAY_SIZE(dsi_dbg_bus_sdm845); } else if (IS_SM8150_TARGET(hwversion) || IS_SM6150_TARGET(hwversion)) { dbg->dbgbus_sde.entries = dbg_bus_sde_sm8150; dbg->dbgbus_sde.cmn.entries_size = ARRAY_SIZE(dbg_bus_sde_sm8150); Loading @@ -4628,6 +5084,8 @@ void sde_dbg_init_dbg_buses(u32 hwversion) dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998; dbg->dbgbus_vbif_rt.cmn.entries_size = ARRAY_SIZE(vbif_dbg_bus_msm8998); dbg->dbgbus_dsi.entries = NULL; dbg->dbgbus_dsi.size = 0; } else { pr_err("unsupported chipset id %X\n", hwversion); } Loading Loading @@ -4655,6 +5113,7 @@ int sde_dbg_init(struct device *dev, struct sde_dbg_power_ctrl *power_ctrl) sde_dbg_base.work_panic = false; sde_dbg_base.panic_on_err = DEFAULT_PANIC; sde_dbg_base.enable_reg_dump = DEFAULT_REGDUMP; memset(&sde_dbg_base.regbuf, 0, sizeof(sde_dbg_base.regbuf)); pr_info("evtlog_status: enable:%d, panic:%d, dump:%d\n", sde_dbg_base.evtlog->enable, sde_dbg_base.panic_on_err, Loading Loading @@ -4688,6 +5147,8 @@ static void sde_dbg_reg_base_destroy(void) */ void sde_dbg_destroy(void) { kfree(sde_dbg_base.regbuf.buf); memset(&sde_dbg_base.regbuf, 0, sizeof(sde_dbg_base.regbuf)); _sde_dbg_debugfs_destroy(); sde_dbg_base_evtlog = NULL; sde_evtlog_destroy(sde_dbg_base.evtlog); Loading
drivers/gpu/drm/msm/sde_dbg.h +13 −4 Original line number Diff line number Diff line Loading @@ -201,11 +201,12 @@ bool sde_evtlog_is_enabled(struct sde_dbg_evtlog *evtlog, u32 flag); * @evtlog_buf: target buffer to print into * @evtlog_buf_size: size of target buffer * @update_last_entry: whether or not to stop at most recent entry * @full_dump: whether to dump full or to limit print entries * Returns: number of bytes written to buffer */ ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, char *evtlog_buf, ssize_t evtlog_buf_size, bool update_last_entry); bool update_last_entry, bool full_dump); /** * sde_dbg_init_dbg_buses - initialize debug bus dumping support for the chipset Loading Loading @@ -329,16 +330,24 @@ void sde_evtlog_set_filter(struct sde_dbg_evtlog *evtlog, char *filter); int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, int index, char *buf, size_t bufsz); #ifndef CONFIG_DRM_SDE_RSC static inline void sde_rsc_debug_dump(u32 mux_sel) { } #else /** * sde_rsc_debug_dump - sde rsc debug dump status * @mux_sel: select mux on rsc debug bus * @mux_sel:» select mux on rsc debug bus */ void sde_rsc_debug_dump(u32 mux_sel); #endif /** * dsi_ctrl_debug_dump - dump dsi debug dump status * @entries: array of debug bus control values * @size: size of the debug bus control array */ void dsi_ctrl_debug_dump(void); void dsi_ctrl_debug_dump(u32 *entries, u32 size); #else static inline struct sde_dbg_evtlog *sde_evtlog_init(void) Loading Loading @@ -430,7 +439,7 @@ static inline void sde_rsc_debug_dump(u32 mux_sel) { } static inline void dsi_ctrl_debug_dump(void) static inline void dsi_ctrl_debug_dump(u32 entries, u32 size) { } Loading
drivers/gpu/drm/msm/sde_dbg_evtlog.c +8 −7 Original line number Diff line number Diff line Loading @@ -101,8 +101,10 @@ void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, const char *name, int line, /* always dump the last entries which are not dumped yet */ static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog, bool update_last_entry) bool update_last_entry, bool full_dump) { int max_entries = full_dump ? SDE_EVTLOG_ENTRY : SDE_EVTLOG_PRINT_ENTRY; if (!evtlog) return false; Loading @@ -120,12 +122,11 @@ static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog, evtlog->last_dump += SDE_EVTLOG_ENTRY; } if ((evtlog->last_dump - evtlog->first) > SDE_EVTLOG_PRINT_ENTRY) { if ((evtlog->last_dump - evtlog->first) > max_entries) { pr_info("evtlog skipping %d entries, last=%d\n", evtlog->last_dump - evtlog->first - SDE_EVTLOG_PRINT_ENTRY, evtlog->last_dump - 1); evtlog->first = evtlog->last_dump - SDE_EVTLOG_PRINT_ENTRY; max_entries, evtlog->last_dump - 1); evtlog->first = evtlog->last_dump - max_entries; } evtlog->next = evtlog->first + 1; Loading @@ -134,7 +135,7 @@ static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog, ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, char *evtlog_buf, ssize_t evtlog_buf_size, bool update_last_entry) bool update_last_entry, bool full_dump) { int i; ssize_t off = 0; Loading @@ -147,7 +148,7 @@ ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, spin_lock_irqsave(&evtlog->spin_lock, flags); /* update markers, exit if nothing to print */ if (!_sde_evtlog_dump_calc_range(evtlog, update_last_entry)) if (!_sde_evtlog_dump_calc_range(evtlog, update_last_entry, full_dump)) goto exit; log = &evtlog->logs[evtlog->first % SDE_EVTLOG_ENTRY]; Loading
drivers/gpu/drm/msm/sde_edid_parser.c +5 −4 Original line number Diff line number Diff line Loading @@ -172,8 +172,9 @@ static const u8 *_sde_edid_find_block(const u8 *in_buf, u32 start_offset, * * edid buffer 1, byte 2 being 0 means no non-DTD/DATA block * collection present and no DTD data present. */ if ((dbc_offset == 0) || (dbc_offset == 4)) { SDE_ERROR("EDID: no DTD or non-DTD data present\n"); SDE_EDID_DEBUG("EDID: no DTD or non-DTD data present\n"); return NULL; } Loading Loading @@ -376,7 +377,7 @@ struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl) edid_ext = sde_find_cea_extension(edid_ctrl->edid); if (!edid_ext) { SDE_ERROR("no cea extension\n"); SDE_DEBUG("no cea extension\n"); return; } Loading Loading @@ -545,7 +546,7 @@ int _sde_edid_update_modes(struct drm_connector *connector, SDE_EDID_DEBUG("%s +", __func__); if (edid_ctrl->edid) { drm_mode_connector_update_edid_property(connector, drm_connector_update_edid_property(connector, edid_ctrl->edid); rc = drm_add_edid_modes(connector, edid_ctrl->edid); Loading @@ -555,7 +556,7 @@ int _sde_edid_update_modes(struct drm_connector *connector, return rc; } drm_mode_connector_update_edid_property(connector, NULL); drm_connector_update_edid_property(connector, NULL); SDE_EDID_DEBUG("%s null edid -", __func__); return rc; } Loading
drivers/gpu/drm/msm/sde_hdcp.h +7 −4 Original line number Diff line number Diff line Loading @@ -33,8 +33,9 @@ enum sde_hdcp_state { enum sde_hdcp_version { HDCP_VERSION_NONE, HDCP_VERSION_1X, HDCP_VERSION_2P2 HDCP_VERSION_1X = BIT(0), HDCP_VERSION_2P2 = BIT(1), HDCP_VERSION_MAX = BIT(2), }; struct sde_hdcp_init_data { Loading Loading @@ -64,6 +65,8 @@ struct sde_hdcp_ops { int (*reauthenticate)(void *input); int (*authenticate)(void *hdcp_ctrl); bool (*feature_supported)(void *input); void (*force_encryption)(void *input, bool enable); bool (*sink_support)(void *input); void (*off)(void *hdcp_ctrl); }; Loading @@ -90,8 +93,8 @@ static inline const char *sde_hdcp_version(enum sde_hdcp_version hdcp_version) void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data); void sde_hdcp_1x_deinit(void *input); struct sde_hdcp_ops *sde_hdcp_1x_start(void *input); struct sde_hdcp_ops *sde_hdcp_1x_get(void *input); void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data); void sde_dp_hdcp2p2_deinit(void *input); struct sde_hdcp_ops *sde_dp_hdcp2p2_start(void *input); struct sde_hdcp_ops *sde_dp_hdcp2p2_get(void *input); #endif /* __SDE_HDCP_H__ */