Loading arch/arm/mach-msm/rpm_rbcpr_stats_v2.c +155 −164 Original line number Diff line number Diff line Loading @@ -42,9 +42,12 @@ enum { CORNER_OFF, CORNER_SVS, CORNER_RETENTION, CORNER_SVS_KRAIT, CORNER_SVS_SOC, CORNER_NOMINAL, CORNER_TURBO, CORNER_SUPER_TURBO, CORNER_MAX, }; Loading @@ -54,7 +57,7 @@ struct rbcpr_recmnd_data_type { }; struct rbcpr_corners_data_type { uint32_t efuse_adjustment; int32_t efuse_adjustment; uint32_t programmed_voltage; uint32_t isr_count; uint32_t min_count; Loading @@ -62,10 +65,12 @@ struct rbcpr_corners_data_type { struct rbcpr_recmnd_data_type rbcpr_recmnd[RBCPR_NUM_RECMNDS]; }; struct rbcpr_rail_stats_type { struct rbcpr_rail_stats_header_type { uint32_t num_corners; uint32_t num_latest_recommends; struct rbcpr_corners_data_type rbcpr_corners[RBCPR_NUM_CORNERS]; }; struct rbcpr_rail_stats_footer_type { uint32_t current_corner; uint32_t railway_voltage; uint32_t off_corner; Loading @@ -75,7 +80,6 @@ struct rbcpr_rail_stats_type { struct rbcpr_stats_type { uint32_t num_rails; uint32_t status; struct rbcpr_rail_stats_type *rbcpr_rail; }; struct rbcpr_data_type { Loading @@ -91,106 +95,158 @@ static char *rbcpr_rail_labels[] = { static char *rbcpr_corner_string[] = { [CORNER_OFF] = "CORNERS_OFF", [CORNER_SVS] = "SVS", [CORNER_RETENTION] = "RETENTION", [CORNER_SVS_KRAIT] = "SVS", [CORNER_SVS_SOC] = "SVS_SOC", [CORNER_NOMINAL] = "NOMINAL", [CORNER_TURBO] = "TURBO", [CORNER_SUPER_TURBO] = "SUPER_TURBO", }; #define CORNER_STRING(a) \ ((a >= CORNER_MAX) ? "INVALID Corner" : rbcpr_corner_string[a]) static struct rbcpr_data_type *rbcpr_data; static struct rbcpr_stats_type *rbcpr_stats; static void msm_rpmrbcpr_read_rpm_data(void) static void msm_rpmrbcpr_print_stats_header( struct rbcpr_stats_type *rbcpr_stats, char *buf, uint32_t *pos) { uint32_t start_offset; uint32_t stats_size; start_offset = offsetof(struct rbcpr_stats_type, rbcpr_rail); stats_size = rbcpr_stats->num_rails * sizeof(struct rbcpr_rail_stats_type); if (stats_size > RBCPR_STATS_MAX_SIZE) { pr_err("%s: Max copy size exceeded. stats size %d max %d", __func__, stats_size, RBCPR_STATS_MAX_SIZE); return; *pos += PRINT(buf, *pos, "\n:RBCPR STATS "); *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rbcpr_stats->num_rails), rbcpr_stats->num_rails); *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rbcpr_stats->status), rbcpr_stats->status); } memcpy_fromio(rbcpr_stats->rbcpr_rail, (rbcpr_data->start + start_offset), stats_size); static void msm_rpmrbcpr_print_rail_header( struct rbcpr_rail_stats_header_type *rail_header, char *buf, uint32_t *pos) { *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rail_header->num_corners), rail_header->num_corners); *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rail_header->num_latest_recommends), rail_header->num_latest_recommends); } static uint32_t msm_rpmrbcpr_print_data(void) static void msm_rpmrbcpr_print_corner_recmnds( struct rbcpr_recmnd_data_type *rbcpr_recmnd, char *buf, uint32_t *pos) { uint32_t pos = 0; uint32_t i, j, k; struct rbcpr_rail_stats_type *rail; struct rbcpr_corners_data_type *corner; struct rbcpr_recmnd_data_type *rbcpr_recmnd; char *buf = rbcpr_data->buf; pos += PRINT(buf, pos, ":RBCPR STATS\n"); pos += PRINT(buf, pos, "(%s: %d)", FIELD(rbcpr_stats->num_rails), rbcpr_stats->num_rails); pos += PRINT(buf, pos, "(%s: %d)\n", FIELD(rbcpr_stats->status), rbcpr_stats->status); *pos += PRINT(buf, *pos, "\n\t\t\t :(%s: %d) ", FIELD(rbcpr_recmd->microvolts), rbcpr_recmnd->microvolts); *pos += PRINT(buf, *pos, " (%s: %lld)", FIELD(rbcpr_recmd->timestamp), rbcpr_recmnd->timestamp); } for (i = 0; i < rbcpr_stats->num_rails; i++) { rail = &rbcpr_stats->rbcpr_rail[i]; pos += PRINT(buf, pos, ":%s Rail Data\n", rbcpr_rail_labels[i]); pos += PRINT(buf, pos, "(%s: %s)", FIELD(rail->current_corner), CORNER_STRING(rail->current_corner)); pos += PRINT(buf, pos, "(%s: %d)", FIELD(rail->railway_voltage), rail->railway_voltage); pos += PRINT(buf, pos, "(%s: %d)", FIELD(rail->off_corner), rail->off_corner); pos += PRINT(buf, pos, "(%s: %d)\n", FIELD(rail->margin), rail->margin); static void msm_rpmrbcpr_print_corner_data( struct rbcpr_corners_data_type *corner, char *buf, uint32_t num_corners, uint32_t *pos) { int i; for (j = 0; j < RBCPR_NUM_CORNERS; j++) { pos += PRINT(buf, pos, "\t\tCorner Data:%s ", CORNER_STRING(j + 1)); corner = &rail->rbcpr_corners[j]; pos += PRINT(buf, pos, "(%s: %d)", *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(corner->efuse_adjustment), corner->efuse_adjustment); pos += PRINT(buf, pos, "(%s: %d)", *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(corner->programmed_voltage), corner->programmed_voltage); pos += PRINT(buf, pos, "(%s: %d)", *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(corner->isr_count), corner->isr_count); pos += PRINT(buf, pos, "(%s: %d)", *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(corner->min_count), corner->min_count); pos += PRINT(buf, pos, "(%s: %d)\n", *pos += PRINT(buf, *pos, "(%s: %d)\n", FIELD(corner->max_count), corner->max_count); *pos += PRINT(buf, *pos, "\t\t\t:Latest Recommends"); for (i = 0; i < num_corners; i++) msm_rpmrbcpr_print_corner_recmnds(&corner->rbcpr_recmnd[i], buf, pos); } for (k = 0; k < RBCPR_NUM_RECMNDS; k++) { rbcpr_recmnd = &corner->rbcpr_recmnd[k]; pos += PRINT(buf, pos, "\t\t\t\tVoltage History[%d] ", k); pos += PRINT(buf, pos, " (%s: %d) ", FIELD(rbcpr_recmd->microvolts), rbcpr_recmnd->microvolts); pos += PRINT(buf, pos, " (%s: %lld)\n", FIELD(rbcpr_recmd->timestamp), rbcpr_recmnd->timestamp); static void msm_rpmrbcpr_print_rail_footer( struct rbcpr_rail_stats_footer_type *rail, char *buf, uint32_t *pos) { *pos += PRINT(buf, *pos, "(%s: %s)", FIELD(rail->current_corner), CORNER_STRING(rail->current_corner)); *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rail->railway_voltage), rail->railway_voltage); *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rail->off_corner), rail->off_corner); *pos += PRINT(buf, *pos, "(%s: %d)\n", FIELD(rail->margin), rail->margin); } static uint32_t msm_rpmrbcpr_read_rpm_data(void) { uint32_t read_offset = 0; static struct rbcpr_stats_type rbcpr_stats_header; uint32_t buffer_offset = 0; char *buf = rbcpr_data->buf; int i, j; memcpy_fromio(&rbcpr_stats_header, rbcpr_data->start, sizeof(rbcpr_stats_header)); read_offset += sizeof(rbcpr_stats_header); msm_rpmrbcpr_print_stats_header(&rbcpr_stats_header, buf, &buffer_offset); for (i = 0; i < rbcpr_stats_header.num_rails; i++) { static struct rbcpr_rail_stats_header_type rail_header; static struct rbcpr_rail_stats_footer_type rail_footer; memcpy_fromio(&rail_header, (rbcpr_data->start + read_offset), sizeof(rail_header)); read_offset += sizeof(rail_header); buffer_offset += PRINT(buf, buffer_offset, "\n:%s Rail Data ", rbcpr_rail_labels[i]); msm_rpmrbcpr_print_rail_header(&rail_header, buf, &buffer_offset); for (j = 0; j < rail_header.num_corners; j++) { static struct rbcpr_corners_data_type corner; uint32_t corner_index; memcpy_fromio(&corner, (rbcpr_data->start + read_offset), sizeof(corner)); read_offset += sizeof(corner); /* * RPM doesn't include corner type in the data for the * corner. For now add this hack to know which corners * are used based on number of corners for the rail. */ corner_index = j + 3; if (rail_header.num_corners == 3 && j == 2) corner_index++; buffer_offset += PRINT(buf, buffer_offset, "\n\t\t:Corner Data: %s ", CORNER_STRING(corner_index)); msm_rpmrbcpr_print_corner_data(&corner, buf, rail_header.num_latest_recommends, &buffer_offset); } buffer_offset += PRINT(buf, buffer_offset, "\n\t\t"); memcpy_fromio(&rail_footer, (rbcpr_data->start + read_offset), sizeof(rail_footer)); read_offset += sizeof(rail_footer); msm_rpmrbcpr_print_rail_footer(&rail_footer, buf, &buffer_offset); } return pos; return buffer_offset; } static int msm_rpmrbcpr_file_read(struct file *file, char __user *bufu, size_t count, loff_t *ppos) static int msm_rpmrbcpr_file_read(struct seq_file *m, void *data) { struct rbcpr_data_type *pdata = file->private_data; struct rbcpr_data_type *pdata = m->private; int ret = 0; int status_counter; int curr_status_counter; static int prev_status_counter; static DEFINE_MUTEX(rbcpr_lock); mutex_lock(&rbcpr_lock); Loading @@ -200,27 +256,17 @@ static int msm_rpmrbcpr_file_read(struct file *file, char __user *bufu, goto exit_rpmrbcpr_file_read; } if (!bufu || count < 0) { pr_err("%s count %d ", __func__, count); ret = -EINVAL; goto exit_rpmrbcpr_file_read; } if (*ppos > pdata->len || !*ppos) { /* Read RPM stats */ status_counter = readl_relaxed(pdata->start + curr_status_counter = readl_relaxed(pdata->start + offsetof(struct rbcpr_stats_type, status)); if (status_counter != rbcpr_stats->status) { msm_rpmrbcpr_read_rpm_data(); rbcpr_stats->status = status_counter; } pdata->len = msm_rpmrbcpr_print_data(); *ppos = 0; if (curr_status_counter != prev_status_counter) { pdata->len = msm_rpmrbcpr_read_rpm_data(); pdata->len = 0; prev_status_counter = curr_status_counter; } /* copy to user data*/ ret = simple_read_from_buffer(bufu, count, ppos, pdata->buf, pdata->len); seq_printf(m, "%s", pdata->buf); exit_rpmrbcpr_file_read: mutex_unlock(&rbcpr_lock); return ret; Loading @@ -228,77 +274,31 @@ exit_rpmrbcpr_file_read: static int msm_rpmrbcpr_file_open(struct inode *inode, struct file *file) { file->private_data = rbcpr_data; if (!rbcpr_data->start) return -ENODEV; return 0; } static int msm_rpmrbcpr_file_close(struct inode *inode, struct file *file) { return 0; return single_open(file, msm_rpmrbcpr_file_read, inode->i_private); } static const struct file_operations msm_rpmrbcpr_fops = { .owner = THIS_MODULE, .open = msm_rpmrbcpr_file_open, .read = msm_rpmrbcpr_file_read, .release = msm_rpmrbcpr_file_close, .llseek = no_llseek, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int msm_rpmrbcpr_memalloc(struct platform_device *pdev) static int msm_rpmrbcpr_validate(struct platform_device *pdev) { void *addr = NULL; int ret = 0; uint32_t num_latest_recommends = 0; uint32_t num_corners = 0; uint32_t num_rails; rbcpr_stats->num_rails = readl_relaxed(rbcpr_data->start); num_rails = readl_relaxed(rbcpr_data->start); if (rbcpr_stats->num_rails > RBCPR_MAX_RAILS) { if (num_rails > RBCPR_MAX_RAILS) { pr_err("%s: Invalid number of RPM RBCPR rails %d", __func__, rbcpr_stats->num_rails); rbcpr_stats->num_rails = 0; ret = -EFAULT; goto rbcpr_memalloc_fail; } rbcpr_stats->rbcpr_rail = devm_kzalloc(&pdev->dev, sizeof(struct rbcpr_rail_stats_type) * rbcpr_stats->num_rails, GFP_KERNEL); if (!rbcpr_stats->rbcpr_rail) { ret = -ENOMEM; goto rbcpr_memalloc_fail; } addr = rbcpr_data->start + offsetof(struct rbcpr_stats_type, rbcpr_rail); /* Each rail has the same number of corners and number of latest recommended values. Read these from the first rail and check them to make sure the values are valid. (RPM doesn't 0 initialize this memory region, so its possible we end up with bogus values if the rbcpr driver is not initialized.). */ num_corners = readl_relaxed(addr); num_latest_recommends = readl_relaxed(addr + offsetof(struct rbcpr_rail_stats_type, num_latest_recommends)); if ((num_latest_recommends != RBCPR_NUM_RECMNDS) || (num_corners != RBCPR_NUM_CORNERS)) { pr_err("%s: Invalid num corners %d, num recmnds %d", __func__, num_corners, num_latest_recommends); __func__, num_rails); ret = -EFAULT; goto rbcpr_memalloc_fail; } rbcpr_memalloc_fail: return ret; } Loading @@ -318,15 +318,6 @@ static int msm_rpmrbcpr_probe(struct platform_device *pdev) if (!rbcpr_data) return -ENOMEM; rbcpr_stats = devm_kzalloc(&pdev->dev, sizeof(struct rbcpr_stats_type), GFP_KERNEL); if (!rbcpr_stats) { pr_err("%s: Failed to allocate memory for RBCPR stats", __func__); return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { Loading Loading @@ -371,13 +362,13 @@ static int msm_rpmrbcpr_probe(struct platform_device *pdev) goto rbcpr_probe_fail; } ret = msm_rpmrbcpr_memalloc(pdev); ret = msm_rpmrbcpr_validate(pdev); if (ret) goto rbcpr_probe_fail; dent = debugfs_create_file("rpm_rbcpr", S_IRUGO, NULL, pdev->dev.platform_data, &msm_rpmrbcpr_fops); rbcpr_data, &msm_rpmrbcpr_fops); if (!dent) { pr_err("%s: error debugfs_create_file failed\n", __func__); Loading Loading
arch/arm/mach-msm/rpm_rbcpr_stats_v2.c +155 −164 Original line number Diff line number Diff line Loading @@ -42,9 +42,12 @@ enum { CORNER_OFF, CORNER_SVS, CORNER_RETENTION, CORNER_SVS_KRAIT, CORNER_SVS_SOC, CORNER_NOMINAL, CORNER_TURBO, CORNER_SUPER_TURBO, CORNER_MAX, }; Loading @@ -54,7 +57,7 @@ struct rbcpr_recmnd_data_type { }; struct rbcpr_corners_data_type { uint32_t efuse_adjustment; int32_t efuse_adjustment; uint32_t programmed_voltage; uint32_t isr_count; uint32_t min_count; Loading @@ -62,10 +65,12 @@ struct rbcpr_corners_data_type { struct rbcpr_recmnd_data_type rbcpr_recmnd[RBCPR_NUM_RECMNDS]; }; struct rbcpr_rail_stats_type { struct rbcpr_rail_stats_header_type { uint32_t num_corners; uint32_t num_latest_recommends; struct rbcpr_corners_data_type rbcpr_corners[RBCPR_NUM_CORNERS]; }; struct rbcpr_rail_stats_footer_type { uint32_t current_corner; uint32_t railway_voltage; uint32_t off_corner; Loading @@ -75,7 +80,6 @@ struct rbcpr_rail_stats_type { struct rbcpr_stats_type { uint32_t num_rails; uint32_t status; struct rbcpr_rail_stats_type *rbcpr_rail; }; struct rbcpr_data_type { Loading @@ -91,106 +95,158 @@ static char *rbcpr_rail_labels[] = { static char *rbcpr_corner_string[] = { [CORNER_OFF] = "CORNERS_OFF", [CORNER_SVS] = "SVS", [CORNER_RETENTION] = "RETENTION", [CORNER_SVS_KRAIT] = "SVS", [CORNER_SVS_SOC] = "SVS_SOC", [CORNER_NOMINAL] = "NOMINAL", [CORNER_TURBO] = "TURBO", [CORNER_SUPER_TURBO] = "SUPER_TURBO", }; #define CORNER_STRING(a) \ ((a >= CORNER_MAX) ? "INVALID Corner" : rbcpr_corner_string[a]) static struct rbcpr_data_type *rbcpr_data; static struct rbcpr_stats_type *rbcpr_stats; static void msm_rpmrbcpr_read_rpm_data(void) static void msm_rpmrbcpr_print_stats_header( struct rbcpr_stats_type *rbcpr_stats, char *buf, uint32_t *pos) { uint32_t start_offset; uint32_t stats_size; start_offset = offsetof(struct rbcpr_stats_type, rbcpr_rail); stats_size = rbcpr_stats->num_rails * sizeof(struct rbcpr_rail_stats_type); if (stats_size > RBCPR_STATS_MAX_SIZE) { pr_err("%s: Max copy size exceeded. stats size %d max %d", __func__, stats_size, RBCPR_STATS_MAX_SIZE); return; *pos += PRINT(buf, *pos, "\n:RBCPR STATS "); *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rbcpr_stats->num_rails), rbcpr_stats->num_rails); *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rbcpr_stats->status), rbcpr_stats->status); } memcpy_fromio(rbcpr_stats->rbcpr_rail, (rbcpr_data->start + start_offset), stats_size); static void msm_rpmrbcpr_print_rail_header( struct rbcpr_rail_stats_header_type *rail_header, char *buf, uint32_t *pos) { *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rail_header->num_corners), rail_header->num_corners); *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rail_header->num_latest_recommends), rail_header->num_latest_recommends); } static uint32_t msm_rpmrbcpr_print_data(void) static void msm_rpmrbcpr_print_corner_recmnds( struct rbcpr_recmnd_data_type *rbcpr_recmnd, char *buf, uint32_t *pos) { uint32_t pos = 0; uint32_t i, j, k; struct rbcpr_rail_stats_type *rail; struct rbcpr_corners_data_type *corner; struct rbcpr_recmnd_data_type *rbcpr_recmnd; char *buf = rbcpr_data->buf; pos += PRINT(buf, pos, ":RBCPR STATS\n"); pos += PRINT(buf, pos, "(%s: %d)", FIELD(rbcpr_stats->num_rails), rbcpr_stats->num_rails); pos += PRINT(buf, pos, "(%s: %d)\n", FIELD(rbcpr_stats->status), rbcpr_stats->status); *pos += PRINT(buf, *pos, "\n\t\t\t :(%s: %d) ", FIELD(rbcpr_recmd->microvolts), rbcpr_recmnd->microvolts); *pos += PRINT(buf, *pos, " (%s: %lld)", FIELD(rbcpr_recmd->timestamp), rbcpr_recmnd->timestamp); } for (i = 0; i < rbcpr_stats->num_rails; i++) { rail = &rbcpr_stats->rbcpr_rail[i]; pos += PRINT(buf, pos, ":%s Rail Data\n", rbcpr_rail_labels[i]); pos += PRINT(buf, pos, "(%s: %s)", FIELD(rail->current_corner), CORNER_STRING(rail->current_corner)); pos += PRINT(buf, pos, "(%s: %d)", FIELD(rail->railway_voltage), rail->railway_voltage); pos += PRINT(buf, pos, "(%s: %d)", FIELD(rail->off_corner), rail->off_corner); pos += PRINT(buf, pos, "(%s: %d)\n", FIELD(rail->margin), rail->margin); static void msm_rpmrbcpr_print_corner_data( struct rbcpr_corners_data_type *corner, char *buf, uint32_t num_corners, uint32_t *pos) { int i; for (j = 0; j < RBCPR_NUM_CORNERS; j++) { pos += PRINT(buf, pos, "\t\tCorner Data:%s ", CORNER_STRING(j + 1)); corner = &rail->rbcpr_corners[j]; pos += PRINT(buf, pos, "(%s: %d)", *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(corner->efuse_adjustment), corner->efuse_adjustment); pos += PRINT(buf, pos, "(%s: %d)", *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(corner->programmed_voltage), corner->programmed_voltage); pos += PRINT(buf, pos, "(%s: %d)", *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(corner->isr_count), corner->isr_count); pos += PRINT(buf, pos, "(%s: %d)", *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(corner->min_count), corner->min_count); pos += PRINT(buf, pos, "(%s: %d)\n", *pos += PRINT(buf, *pos, "(%s: %d)\n", FIELD(corner->max_count), corner->max_count); *pos += PRINT(buf, *pos, "\t\t\t:Latest Recommends"); for (i = 0; i < num_corners; i++) msm_rpmrbcpr_print_corner_recmnds(&corner->rbcpr_recmnd[i], buf, pos); } for (k = 0; k < RBCPR_NUM_RECMNDS; k++) { rbcpr_recmnd = &corner->rbcpr_recmnd[k]; pos += PRINT(buf, pos, "\t\t\t\tVoltage History[%d] ", k); pos += PRINT(buf, pos, " (%s: %d) ", FIELD(rbcpr_recmd->microvolts), rbcpr_recmnd->microvolts); pos += PRINT(buf, pos, " (%s: %lld)\n", FIELD(rbcpr_recmd->timestamp), rbcpr_recmnd->timestamp); static void msm_rpmrbcpr_print_rail_footer( struct rbcpr_rail_stats_footer_type *rail, char *buf, uint32_t *pos) { *pos += PRINT(buf, *pos, "(%s: %s)", FIELD(rail->current_corner), CORNER_STRING(rail->current_corner)); *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rail->railway_voltage), rail->railway_voltage); *pos += PRINT(buf, *pos, "(%s: %d)", FIELD(rail->off_corner), rail->off_corner); *pos += PRINT(buf, *pos, "(%s: %d)\n", FIELD(rail->margin), rail->margin); } static uint32_t msm_rpmrbcpr_read_rpm_data(void) { uint32_t read_offset = 0; static struct rbcpr_stats_type rbcpr_stats_header; uint32_t buffer_offset = 0; char *buf = rbcpr_data->buf; int i, j; memcpy_fromio(&rbcpr_stats_header, rbcpr_data->start, sizeof(rbcpr_stats_header)); read_offset += sizeof(rbcpr_stats_header); msm_rpmrbcpr_print_stats_header(&rbcpr_stats_header, buf, &buffer_offset); for (i = 0; i < rbcpr_stats_header.num_rails; i++) { static struct rbcpr_rail_stats_header_type rail_header; static struct rbcpr_rail_stats_footer_type rail_footer; memcpy_fromio(&rail_header, (rbcpr_data->start + read_offset), sizeof(rail_header)); read_offset += sizeof(rail_header); buffer_offset += PRINT(buf, buffer_offset, "\n:%s Rail Data ", rbcpr_rail_labels[i]); msm_rpmrbcpr_print_rail_header(&rail_header, buf, &buffer_offset); for (j = 0; j < rail_header.num_corners; j++) { static struct rbcpr_corners_data_type corner; uint32_t corner_index; memcpy_fromio(&corner, (rbcpr_data->start + read_offset), sizeof(corner)); read_offset += sizeof(corner); /* * RPM doesn't include corner type in the data for the * corner. For now add this hack to know which corners * are used based on number of corners for the rail. */ corner_index = j + 3; if (rail_header.num_corners == 3 && j == 2) corner_index++; buffer_offset += PRINT(buf, buffer_offset, "\n\t\t:Corner Data: %s ", CORNER_STRING(corner_index)); msm_rpmrbcpr_print_corner_data(&corner, buf, rail_header.num_latest_recommends, &buffer_offset); } buffer_offset += PRINT(buf, buffer_offset, "\n\t\t"); memcpy_fromio(&rail_footer, (rbcpr_data->start + read_offset), sizeof(rail_footer)); read_offset += sizeof(rail_footer); msm_rpmrbcpr_print_rail_footer(&rail_footer, buf, &buffer_offset); } return pos; return buffer_offset; } static int msm_rpmrbcpr_file_read(struct file *file, char __user *bufu, size_t count, loff_t *ppos) static int msm_rpmrbcpr_file_read(struct seq_file *m, void *data) { struct rbcpr_data_type *pdata = file->private_data; struct rbcpr_data_type *pdata = m->private; int ret = 0; int status_counter; int curr_status_counter; static int prev_status_counter; static DEFINE_MUTEX(rbcpr_lock); mutex_lock(&rbcpr_lock); Loading @@ -200,27 +256,17 @@ static int msm_rpmrbcpr_file_read(struct file *file, char __user *bufu, goto exit_rpmrbcpr_file_read; } if (!bufu || count < 0) { pr_err("%s count %d ", __func__, count); ret = -EINVAL; goto exit_rpmrbcpr_file_read; } if (*ppos > pdata->len || !*ppos) { /* Read RPM stats */ status_counter = readl_relaxed(pdata->start + curr_status_counter = readl_relaxed(pdata->start + offsetof(struct rbcpr_stats_type, status)); if (status_counter != rbcpr_stats->status) { msm_rpmrbcpr_read_rpm_data(); rbcpr_stats->status = status_counter; } pdata->len = msm_rpmrbcpr_print_data(); *ppos = 0; if (curr_status_counter != prev_status_counter) { pdata->len = msm_rpmrbcpr_read_rpm_data(); pdata->len = 0; prev_status_counter = curr_status_counter; } /* copy to user data*/ ret = simple_read_from_buffer(bufu, count, ppos, pdata->buf, pdata->len); seq_printf(m, "%s", pdata->buf); exit_rpmrbcpr_file_read: mutex_unlock(&rbcpr_lock); return ret; Loading @@ -228,77 +274,31 @@ exit_rpmrbcpr_file_read: static int msm_rpmrbcpr_file_open(struct inode *inode, struct file *file) { file->private_data = rbcpr_data; if (!rbcpr_data->start) return -ENODEV; return 0; } static int msm_rpmrbcpr_file_close(struct inode *inode, struct file *file) { return 0; return single_open(file, msm_rpmrbcpr_file_read, inode->i_private); } static const struct file_operations msm_rpmrbcpr_fops = { .owner = THIS_MODULE, .open = msm_rpmrbcpr_file_open, .read = msm_rpmrbcpr_file_read, .release = msm_rpmrbcpr_file_close, .llseek = no_llseek, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int msm_rpmrbcpr_memalloc(struct platform_device *pdev) static int msm_rpmrbcpr_validate(struct platform_device *pdev) { void *addr = NULL; int ret = 0; uint32_t num_latest_recommends = 0; uint32_t num_corners = 0; uint32_t num_rails; rbcpr_stats->num_rails = readl_relaxed(rbcpr_data->start); num_rails = readl_relaxed(rbcpr_data->start); if (rbcpr_stats->num_rails > RBCPR_MAX_RAILS) { if (num_rails > RBCPR_MAX_RAILS) { pr_err("%s: Invalid number of RPM RBCPR rails %d", __func__, rbcpr_stats->num_rails); rbcpr_stats->num_rails = 0; ret = -EFAULT; goto rbcpr_memalloc_fail; } rbcpr_stats->rbcpr_rail = devm_kzalloc(&pdev->dev, sizeof(struct rbcpr_rail_stats_type) * rbcpr_stats->num_rails, GFP_KERNEL); if (!rbcpr_stats->rbcpr_rail) { ret = -ENOMEM; goto rbcpr_memalloc_fail; } addr = rbcpr_data->start + offsetof(struct rbcpr_stats_type, rbcpr_rail); /* Each rail has the same number of corners and number of latest recommended values. Read these from the first rail and check them to make sure the values are valid. (RPM doesn't 0 initialize this memory region, so its possible we end up with bogus values if the rbcpr driver is not initialized.). */ num_corners = readl_relaxed(addr); num_latest_recommends = readl_relaxed(addr + offsetof(struct rbcpr_rail_stats_type, num_latest_recommends)); if ((num_latest_recommends != RBCPR_NUM_RECMNDS) || (num_corners != RBCPR_NUM_CORNERS)) { pr_err("%s: Invalid num corners %d, num recmnds %d", __func__, num_corners, num_latest_recommends); __func__, num_rails); ret = -EFAULT; goto rbcpr_memalloc_fail; } rbcpr_memalloc_fail: return ret; } Loading @@ -318,15 +318,6 @@ static int msm_rpmrbcpr_probe(struct platform_device *pdev) if (!rbcpr_data) return -ENOMEM; rbcpr_stats = devm_kzalloc(&pdev->dev, sizeof(struct rbcpr_stats_type), GFP_KERNEL); if (!rbcpr_stats) { pr_err("%s: Failed to allocate memory for RBCPR stats", __func__); return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { Loading Loading @@ -371,13 +362,13 @@ static int msm_rpmrbcpr_probe(struct platform_device *pdev) goto rbcpr_probe_fail; } ret = msm_rpmrbcpr_memalloc(pdev); ret = msm_rpmrbcpr_validate(pdev); if (ret) goto rbcpr_probe_fail; dent = debugfs_create_file("rpm_rbcpr", S_IRUGO, NULL, pdev->dev.platform_data, &msm_rpmrbcpr_fops); rbcpr_data, &msm_rpmrbcpr_fops); if (!dent) { pr_err("%s: error debugfs_create_file failed\n", __func__); Loading